mapFolding 0.2.4__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/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
 
@@ -232,6 +242,40 @@ def parseDimensions(dimensions: Sequence[int], parameterName: str = 'unnamed par
232
242
 
233
243
  return listNonNegative
234
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
+
235
279
  def setCPUlimit(CPUlimit: Union[bool, float, int, None]) -> int:
236
280
  """Sets CPU limit for Numba concurrent operations. Note that it can only affect Numba-jitted functions that have not yet been imported.
237
281
 
@@ -1,12 +1,7 @@
1
- # useLovelace = True
2
- useLovelace = False
1
+ from mapFolding.lovelace import countSequential
2
+ from mapFolding.lovelace import countParallel
3
+ from mapFolding.lovelace import countInitialize
3
4
 
4
- if useLovelace:
5
- from mapFolding.lovelace import countSequential
6
- from mapFolding.lovelace import countParallel
7
- from mapFolding.lovelace import countInitialize
8
-
9
- else:
10
- from mapFolding.countSequential import countSequential
11
- from mapFolding.countParallel import countParallel
12
- from mapFolding.countInitialize import countInitialize
5
+ # from mapFolding.countSequential import countSequential
6
+ # from mapFolding.countParallel import countParallel
7
+ # from mapFolding.countInitialize import countInitialize
@@ -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
@@ -1,19 +1,22 @@
1
1
  from mapFolding import indexMy, indexThe, indexTrack
2
2
  import ast
3
+ import copy
3
4
  import pathlib
4
5
 
5
- dictionaryEnumValues = {}
6
- for enumIndex in [indexMy, indexThe, indexTrack]:
7
- for memberName, memberValue in enumIndex._member_map_.items():
8
- dictionaryEnumValues[f"{enumIndex.__name__}.{memberName}.value"] = memberValue.value
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
9
12
 
10
- class RecursiveInliner(ast.NodeTransformer):
13
+ class RecursiveInlinerWithEnum(ast.NodeTransformer):
11
14
  def __init__(self, dictionaryFunctions, dictionaryEnumValues):
12
15
  self.dictionaryFunctions = dictionaryFunctions
13
16
  self.dictionaryEnumValues = dictionaryEnumValues
14
17
  self.processed = set() # Track processed functions to avoid infinite recursion
15
18
 
16
- def inline_function_body(self, functionName):
19
+ def inlineFunctionBody(self, functionName):
17
20
  if functionName in self.processed:
18
21
  return None
19
22
 
@@ -35,7 +38,7 @@ class RecursiveInliner(ast.NodeTransformer):
35
38
  def visit_Call(self, node):
36
39
  callNode = self.generic_visit(node)
37
40
  if isinstance(callNode, ast.Call) and isinstance(callNode.func, ast.Name) and callNode.func.id in self.dictionaryFunctions:
38
- inlineDefinition = self.inline_function_body(callNode.func.id)
41
+ inlineDefinition = self.inlineFunctionBody(callNode.func.id)
39
42
  if inlineDefinition and inlineDefinition.body:
40
43
  lastStmt = inlineDefinition.body[-1]
41
44
  if isinstance(lastStmt, ast.Return) and lastStmt.value is not None:
@@ -48,23 +51,23 @@ class RecursiveInliner(ast.NodeTransformer):
48
51
  def visit_Expr(self, node):
49
52
  if isinstance(node.value, ast.Call):
50
53
  if isinstance(node.value.func, ast.Name) and node.value.func.id in self.dictionaryFunctions:
51
- inlineDefinition = self.inline_function_body(node.value.func.id)
54
+ inlineDefinition = self.inlineFunctionBody(node.value.func.id)
52
55
  if inlineDefinition:
53
56
  return [self.visit(stmt) for stmt in inlineDefinition.body]
54
57
  return self.generic_visit(node)
55
58
 
56
- def find_required_imports(node):
57
- """Find all modules that need to be imported based on AST analysis."""
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."""
58
62
  requiredImports = set()
59
63
 
60
64
  class ImportFinder(ast.NodeVisitor):
61
65
  def visit_Name(self, node):
62
- # Common modules we might need
63
66
  if node.id in {'numba'}:
64
67
  requiredImports.add(node.id)
65
68
  self.generic_visit(node)
66
69
 
67
- def visit_Decorator(self, node):
70
+ def visitDecorator(self, node):
68
71
  if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
69
72
  if node.func.id == 'jit':
70
73
  requiredImports.add('numba')
@@ -73,7 +76,7 @@ def find_required_imports(node):
73
76
  ImportFinder().visit(node)
74
77
  return requiredImports
75
78
 
76
- def generate_imports(requiredImports):
79
+ def generateImports(requiredImports):
77
80
  """Generate import statements based on required modules."""
78
81
  importStatements = []
79
82
 
@@ -88,7 +91,7 @@ def generate_imports(requiredImports):
88
91
 
89
92
  return '\n'.join(importStatements)
90
93
 
91
- def inline_functions(sourceCode, targetFunctionName, dictionaryEnumValues):
94
+ def inlineFunctions(sourceCode, targetFunctionName, dictionaryEnumValues):
92
95
  dictionaryParsed = ast.parse(sourceCode)
93
96
  dictionaryFunctions = {
94
97
  element.name: element
@@ -96,29 +99,54 @@ def inline_functions(sourceCode, targetFunctionName, dictionaryEnumValues):
96
99
  if isinstance(element, ast.FunctionDef)
97
100
  }
98
101
  nodeTarget = dictionaryFunctions[targetFunctionName]
99
- nodeInliner = RecursiveInliner(dictionaryFunctions, dictionaryEnumValues)
102
+ nodeInliner = RecursiveInlinerWithEnum(dictionaryFunctions, dictionaryEnumValues)
100
103
  nodeInlined = nodeInliner.visit(nodeTarget)
101
104
  ast.fix_missing_locations(nodeInlined)
102
105
 
103
106
  # Generate imports
104
- requiredImports = find_required_imports(nodeInlined)
105
- importStatements = generate_imports(requiredImports)
107
+ requiredImports = findRequiredImports(nodeInlined)
108
+ importStatements = generateImports(requiredImports)
106
109
 
107
110
  # Combine imports with inlined code
108
111
  inlinedCode = importStatements + '\n\n' + ast.unparse(ast.Module(body=[nodeInlined], type_ignores=[]))
109
112
  return inlinedCode
110
113
 
111
- pathFilenameSource = pathlib.Path("/apps/mapFolding/mapFolding/lovelace.py")
112
- codeSource = pathFilenameSource.read_text()
113
-
114
- listCallables = [
115
- 'countSequential',
116
- 'countParallel',
117
- 'countInitialize',
118
- ]
119
- listPathFilenamesDestination = []
120
- for callableTarget in listCallables:
121
- pathFilenameDestination = pathFilenameSource.with_stem(callableTarget)
122
- codeInlined = inline_functions(codeSource, callableTarget, dictionaryEnumValues)
123
- pathFilenameDestination.write_text(codeInlined)
124
- listPathFilenamesDestination.append(pathFilenameDestination)
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)
@@ -0,0 +1,99 @@
1
+ """NOTE make a special venv for nuitka, then run nuitka from that venv"""
2
+ from pathlib import Path
3
+ from pickle import loads
4
+ from typing import Final
5
+ import numpy
6
+ from mapFolding.someAssemblyRequired.jobsAndTasks import Z0Z_makeJob
7
+
8
+ """
9
+ Section: configure every time"""
10
+
11
+ # TODO configure this
12
+ mapShape = [3]*3
13
+ # NOTE ^^^^^^ pay attention
14
+
15
+ """
16
+ Section: settings"""
17
+
18
+ pathFilenameData = Z0Z_makeJob(mapShape)
19
+
20
+ pathJob = pathFilenameData.parent
21
+
22
+ pathFilenameAlgorithm = Path('/apps/mapFolding/mapFolding/countSequentialNoNumba.py')
23
+ pathFilenameDestination = Path(f"/apps/mapFolding/nn/{pathJob.name}.py")
24
+
25
+ """
26
+ Section: did you handle and include this stuff?"""
27
+
28
+ lineImportNumPy = "import numpy"
29
+ linePrintFoldsTotal = "print(foldsSubTotals.sum().item())"
30
+ linesAlgorithm = """"""
31
+ linesData = """"""
32
+ settingsNuitkaProject=f"""
33
+ # nuitka-project: --mode=onefile
34
+ # nuitka-project: --onefile-no-compression
35
+ # nuitka-project: --lto=yes
36
+ # nuitka-project: --clang
37
+ # nuitka-project: --output-dir={pathJob}
38
+ # nuitka-project: --output-filename={pathJob.name}.exe
39
+ """
40
+ # nuitka-project:
41
+ """
42
+ Section: do the work"""
43
+
44
+ WTFamIdoing = pathFilenameAlgorithm.read_text()
45
+ for lineSource in WTFamIdoing.splitlines():
46
+ ImaIndent = ' '
47
+ if lineSource.startswith(ImaIndent):
48
+ lineSource = lineSource[len(ImaIndent):None]
49
+ elif lineSource.startswith('#'):
50
+ continue
51
+ elif not lineSource:
52
+ continue
53
+ elif lineSource.startswith('def '):
54
+ continue
55
+ else:
56
+ raise NotImplementedError("You didn't anticipate this.")
57
+ linesAlgorithm = "\n".join([linesAlgorithm
58
+ , lineSource
59
+ ])
60
+
61
+ stateJob = loads(pathFilenameData.read_bytes())
62
+ connectionGraph: Final[numpy.ndarray] = stateJob['connectionGraph']
63
+ foldsSubTotals: numpy.ndarray = stateJob['foldsSubTotals']
64
+ gapsWhere: numpy.ndarray = stateJob['gapsWhere']
65
+ my: numpy.ndarray = stateJob['my']
66
+ the: numpy.ndarray = stateJob['the']
67
+ track: numpy.ndarray = stateJob['track']
68
+
69
+ pathFilenameFoldsTotal = stateJob['pathFilenameFoldsTotal']
70
+ lineDataPathFilenameFoldsTotal = "pathFilenameFoldsTotal = r'" + str(pathFilenameFoldsTotal) + "'\n"
71
+
72
+ def archivistFormatsArrayToCode(arrayTarget: numpy.ndarray, identifierName: str) -> str:
73
+ """Format numpy array into a code string that recreates the array."""
74
+ arrayAsTypeStr = numpy.array2string(
75
+ arrayTarget,
76
+ threshold=10000,
77
+ max_line_width=100,
78
+ separator=','
79
+ )
80
+ return f"{identifierName} = numpy.array({arrayAsTypeStr}, dtype=numpy.{arrayTarget.dtype})\n"
81
+
82
+ linesData = "\n".join([linesData
83
+ , lineDataPathFilenameFoldsTotal
84
+ , archivistFormatsArrayToCode(the, 'the')
85
+ , archivistFormatsArrayToCode(my, 'my')
86
+ , archivistFormatsArrayToCode(foldsSubTotals, 'foldsSubTotals')
87
+ , archivistFormatsArrayToCode(gapsWhere, 'gapsWhere')
88
+ , archivistFormatsArrayToCode(connectionGraph, 'connectionGraph')
89
+ , archivistFormatsArrayToCode(track, 'track')
90
+ ])
91
+
92
+ linesAll = "\n".join([settingsNuitkaProject
93
+ , lineImportNumPy
94
+ , linesData
95
+ , linesAlgorithm
96
+ , linePrintFoldsTotal
97
+ ])
98
+
99
+ pathFilenameDestination.write_text(linesAll)
@@ -0,0 +1,121 @@
1
+ """Create a python module hardcoded to compute a map's foldsTotal.
2
+ NumPy ndarray.
3
+ Numba optimized.
4
+ Absolutely no other imports.
5
+ """
6
+ from mapFolding import datatypeLarge, dtypeLarge, dtypeDefault
7
+ from mapFolding.someAssemblyRequired.inlineAfunction import Z0Z_inlineMapFolding
8
+ from mapFolding.someAssemblyRequired.jobsAndTasks import Z0Z_makeJob
9
+ import importlib
10
+ import llvmlite.binding
11
+ import numpy
12
+ import pathlib
13
+ import pickle
14
+
15
+ listDimensions = [3,7]
16
+
17
+ # NOTE this overwrites files
18
+ Z0Z_inlineMapFolding()
19
+
20
+ identifierCallableLaunch = "goGoGadgetAbsurdity"
21
+
22
+ def archivistFormatsArrayToCode(arrayTarget: numpy.ndarray, identifierName: str) -> str:
23
+ """Format numpy array into a code string that recreates the array."""
24
+ arrayAsTypeStr = numpy.array2string(arrayTarget, threshold=10000, max_line_width=200, separator=',')
25
+ return f"{identifierName} = numpy.array({arrayAsTypeStr}, dtype=numpy.{arrayTarget.dtype})"
26
+
27
+ def writeModuleWithNumba(listDimensions):
28
+ numpy_dtypeLarge = dtypeLarge
29
+ numpy_dtypeDefault = dtypeDefault
30
+
31
+ parametersNumba = f"numba.types.{datatypeLarge}(), cache=True, parallel=False, boundscheck=False, \
32
+ error_model='numpy', fastmath=True, nogil=True, nopython=True, _nrt=True, forceinline=True, \
33
+ inline=True, looplift=True, no_cfunc_wrapper=False, no_cpython_wrapper=False"
34
+
35
+ pathFilenameData = Z0Z_makeJob(listDimensions, datatypeDefault=numpy_dtypeDefault, datatypeLarge=numpy_dtypeLarge)
36
+
37
+ pathFilenameAlgorithm = pathlib.Path('/apps/mapFolding/mapFolding/countSequentialNoNumba.py')
38
+ pathFilenameDestination = pathFilenameData.with_stem(pathFilenameData.parent.name).with_suffix(".py")
39
+
40
+ lineNumba = f"@numba.jit({parametersNumba})"
41
+
42
+ linesImport = "\n".join([
43
+ "import numpy"
44
+ , "import numba"
45
+ ])
46
+
47
+ stateJob = pickle.loads(pathFilenameData.read_bytes())
48
+
49
+ ImaIndent = ' '
50
+ linesDataDynamic = """"""
51
+ linesDataDynamic = "\n".join([linesDataDynamic
52
+ , ImaIndent + archivistFormatsArrayToCode(stateJob['my'], 'my')
53
+ , ImaIndent + archivistFormatsArrayToCode(stateJob['foldsSubTotals'], 'foldsSubTotals')
54
+ , ImaIndent + archivistFormatsArrayToCode(stateJob['gapsWhere'], 'gapsWhere')
55
+ , ImaIndent + archivistFormatsArrayToCode(stateJob['track'], 'track')
56
+ ])
57
+
58
+ linesDataStatic = """"""
59
+ linesDataStatic = "\n".join([linesDataStatic
60
+ , ImaIndent + archivistFormatsArrayToCode(stateJob['the'], 'the')
61
+ , ImaIndent + archivistFormatsArrayToCode(stateJob['connectionGraph'], 'connectionGraph')
62
+ ])
63
+
64
+ pathFilenameFoldsTotal: pathlib.Path = stateJob['pathFilenameFoldsTotal']
65
+
66
+ linesAlgorithm = """"""
67
+ for lineSource in pathFilenameAlgorithm.read_text().splitlines():
68
+ if lineSource.startswith('#'):
69
+ continue
70
+ elif not lineSource:
71
+ continue
72
+ elif lineSource.startswith('def '):
73
+ lineSource = "\n".join([lineNumba
74
+ , f"def {identifierCallableLaunch}():"
75
+ , linesDataDynamic
76
+ , linesDataStatic
77
+ ])
78
+ linesAlgorithm = "\n".join([linesAlgorithm
79
+ , lineSource
80
+ ])
81
+
82
+ lineReturn = f"{ImaIndent}return foldsSubTotals.sum().item()"
83
+
84
+ linesLaunch = """"""
85
+ linesLaunch = linesLaunch + f"""
86
+ if __name__ == '__main__':
87
+ foldsTotal = {identifierCallableLaunch}()"""
88
+
89
+ linesWriteFoldsTotal = """"""
90
+ linesWriteFoldsTotal = "\n".join([linesWriteFoldsTotal
91
+ , " print(foldsTotal)"
92
+ , f" open('{pathFilenameFoldsTotal.as_posix()}', 'w').write(str(foldsTotal))"
93
+ ])
94
+
95
+ linesAll = "\n".join([
96
+ linesImport
97
+ , linesAlgorithm
98
+ , f"{ImaIndent}print(foldsSubTotals.sum().item())"
99
+ , lineReturn
100
+ , linesLaunch
101
+ , linesWriteFoldsTotal
102
+ ])
103
+
104
+ pathFilenameDestination.write_text(linesAll)
105
+
106
+ return pathFilenameDestination
107
+
108
+ def writeModuleLLVM(pathFilenamePythonFile: pathlib.Path) -> pathlib.Path:
109
+ pathRootPackage = pathlib.Path('c:/apps/mapFolding')
110
+ relativePathModule = pathFilenamePythonFile.relative_to(pathRootPackage)
111
+ moduleTarget = '.'.join(relativePathModule.parts)[0:-len(relativePathModule.suffix)]
112
+ moduleTargetImported = importlib.import_module(moduleTarget)
113
+ linesLLVM = moduleTargetImported.__dict__[identifierCallableLaunch].inspect_llvm()[()]
114
+ moduleLLVM = llvmlite.binding.module.parse_assembly(linesLLVM)
115
+ pathFilenameLLVM = pathFilenamePythonFile.with_suffix(".ll")
116
+ pathFilenameLLVM.write_text(str(moduleLLVM))
117
+ return pathFilenameLLVM
118
+
119
+ if __name__ == '__main__':
120
+ pathFilenamePythonFile = writeModuleWithNumba(listDimensions)
121
+ pathFilenameLLVM = writeModuleLLVM(pathFilenamePythonFile)
mapFolding/startHere.py CHANGED
@@ -1,15 +1,14 @@
1
- from mapFolding import outfitCountFolds, getFilenameFoldsTotal
2
- from typing import Optional, Sequence, Type, Union
1
+ from mapFolding import outfitCountFolds, getPathFilenameFoldsTotal, saveFoldsTotal
2
+ from typing import Any, Optional, Sequence, Type, Union
3
3
  import os
4
- import pathlib
5
4
 
6
- def countFolds(listDimensions: Sequence[int], writeFoldsTotal: Optional[Union[str, os.PathLike[str]]] = None, computationDivisions: Optional[Union[int, str]] = None, CPUlimit: Optional[Union[int, float, bool]] = None, **keywordArguments: Optional[Type]) -> int:
5
+ def countFolds(listDimensions: Sequence[int], pathishWriteFoldsTotal: Optional[Union[str, os.PathLike[str]]] = None, computationDivisions: Optional[Union[int, str]] = None, CPUlimit: Optional[Union[int, float, bool]] = None, **keywordArguments: Optional[Type[Any]]) -> int:
7
6
  """Count the total number of possible foldings for a given map dimensions.
8
7
 
9
8
  Parameters:
10
9
  listDimensions: List of integers representing the dimensions of the map to be folded.
11
- writeFoldsTotal (None): Path or filename to write the total fold count.
12
- If a directory is provided, creates a file with default name based on map dimensions.
10
+ pathishWriteFoldsTotal (None): Path, filename, or pathFilename to write the total fold count to.
11
+ If a directory is provided, creates a file with a default name based on map dimensions.
13
12
  computationDivisions (None):
14
13
  Whether and how to divide the computational work. See notes for details.
15
14
  CPUlimit (None): This is only relevant if there are `computationDivisions`: whether and how to limit the CPU usage. See notes for details.
@@ -37,12 +36,8 @@ def countFolds(listDimensions: Sequence[int], writeFoldsTotal: Optional[Union[st
37
36
  stateUniversal = outfitCountFolds(listDimensions, computationDivisions=computationDivisions, CPUlimit=CPUlimit, **keywordArguments)
38
37
 
39
38
  pathFilenameFoldsTotal = None
40
- if writeFoldsTotal is not None:
41
- pathFilenameFoldsTotal = pathlib.Path(writeFoldsTotal)
42
- if pathFilenameFoldsTotal.is_dir():
43
- filenameFoldsTotalDEFAULT = getFilenameFoldsTotal(stateUniversal['mapShape'])
44
- pathFilenameFoldsTotal = pathFilenameFoldsTotal / filenameFoldsTotalDEFAULT
45
- pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
39
+ if pathishWriteFoldsTotal is not None:
40
+ pathFilenameFoldsTotal = getPathFilenameFoldsTotal(stateUniversal['mapShape'], pathishWriteFoldsTotal)
46
41
 
47
42
  from mapFolding.babbage import _countFolds
48
43
  _countFolds(**stateUniversal)
@@ -50,10 +45,6 @@ def countFolds(listDimensions: Sequence[int], writeFoldsTotal: Optional[Union[st
50
45
  foldsTotal = stateUniversal['foldsSubTotals'].sum().item()
51
46
 
52
47
  if pathFilenameFoldsTotal is not None:
53
- try:
54
- pathFilenameFoldsTotal.write_text(str(foldsTotal))
55
- except Exception as ERRORmessage:
56
- print(ERRORmessage)
57
- print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal")
48
+ saveFoldsTotal(pathFilenameFoldsTotal, foldsTotal)
58
49
 
59
50
  return foldsTotal
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mapFolding
3
- Version: 0.2.4
4
- Summary: Algorithm(s) for counting distinct ways to fold a map (or a strip of stamps)
3
+ Version: 0.2.5
4
+ Summary: Count distinct ways to fold a map (or a strip of stamps)
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  Project-URL: homepage, https://github.com/hunterhogan/mapFolding
7
7
  Requires-Python: <3.13,>=3.10
@@ -14,16 +14,11 @@ Requires-Dist: pandas; extra == "benchmark"
14
14
  Requires-Dist: jupyter; extra == "benchmark"
15
15
  Requires-Dist: ipywidgets; extra == "benchmark"
16
16
  Requires-Dist: tqdm; extra == "benchmark"
17
- Provides-Extra: jax
18
- Requires-Dist: jax; extra == "jax"
19
- Requires-Dist: jaxtyping; extra == "jax"
20
17
  Provides-Extra: testing
21
18
  Requires-Dist: pytest; extra == "testing"
22
19
  Requires-Dist: pytest-cov; extra == "testing"
23
20
  Requires-Dist: pytest-env; extra == "testing"
24
21
  Requires-Dist: pytest-xdist; extra == "testing"
25
- Requires-Dist: pytest-order; extra == "testing"
26
- Requires-Dist: pytest-dependency; extra == "testing"
27
22
 
28
23
  # Algorithm(s) for counting distinct ways to fold a map (or a strip of stamps)
29
24
 
@@ -41,7 +36,7 @@ The directory [mapFolding/reference](https://github.com/hunterhogan/mapFolding/b
41
36
  - [hunterNumba.py](https://github.com/hunterhogan/mapFolding/blob/main/mapFolding/reference), a one-size-fits-all, self-contained, reasonably fast, contemporary algorithm that is nevertheless infected by _noobaceae ignorancium_, and
42
37
  - miscellaneous notes.
43
38
 
44
- [![Python Tests](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml/badge.svg)](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml) [![pip install mapFolding](https://img.shields.io/badge/pip%20install-mapFolding-gray.svg?colorB=3b434b)](https://pypi.org/project/mapFolding/) ![Static Badge](https://img.shields.io/badge/stinkin'%20badges-don't%20need-b98e5e) ![PyPI - Downloads](https://img.shields.io/pypi/dd/mapFolding) ![Static Badge](https://img.shields.io/badge/issues-I%20have%20them-brightgreen) ![GitHub repo size](https://img.shields.io/github/repo-size/hunterhogan/mapFolding)
39
+ [![pip install mapFolding](https://img.shields.io/badge/pip%20install-mapFolding-gray.svg?colorB=3b434b)](https://pypi.org/project/mapFolding/) [![Python Tests](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml/badge.svg)](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml) [![Static Badge](https://img.shields.io/badge/stinkin'%20badges-don't%20need-b98e5e)](https://youtu.be/g6f_miE91mk&t=4) ![PyPI - Downloads](https://img.shields.io/pypi/dd/mapFolding) ![Static Badge](https://img.shields.io/badge/issues-I%20have%20them-brightgreen) ![GitHub repo size](https://img.shields.io/github/repo-size/hunterhogan/mapFolding)
45
40
 
46
41
  ## Simple, easy usage based on OEIS IDs
47
42
 
@@ -133,3 +128,8 @@ In [`foldings.txt`](https://github.com/hunterhogan/mapFolding/blob/main/mapFoldi
133
128
  ```sh
134
129
  pip install mapFolding
135
130
  ```
131
+
132
+ ## My recovery
133
+
134
+ [![Static Badge](https://img.shields.io/badge/2011_August-Homeless_since-blue?style=flat)](https://HunterThinks.com/support)
135
+ [![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UC3Gx7kz61009NbhpRtPP7tw)](https://www.youtube.com/@HunterHogan)
@@ -1,35 +1,33 @@
1
- mapFolding/__init__.py,sha256=wnf2EzHR2unVha6-Y0gRoSPaE4PDdT4VngINa_dfT2E,337
1
+ mapFolding/__init__.py,sha256=yZ_rcMMCco346M62nKzp90GPp9OV1UkkWSxKzP3ISPA,380
2
2
  mapFolding/babbage.py,sha256=51fO7lwcTsTvSMwzKW1G2nGslGoEQt19IgnqZi8znao,2222
3
- mapFolding/beDRY.py,sha256=XawGabR1vhzOfdA46HSXmisA5EmxisTKdA3D98KDeac,13699
4
- mapFolding/countInitialize.py,sha256=pIeH52OwDMfuHXT2T4BbPmMm6r7zJnGc-e0QVQCKyDc,1824
5
- mapFolding/countParallel.py,sha256=1sLGIlMj_xZ4bFkG1srOPcDUCrSKc1q3x2QN_8l_sgY,2451
6
- mapFolding/countSequential.py,sha256=QSXwK3o8YBcxNrir_wGMXgqp38hXYTJanYXFLxUPCPo,1993
7
- mapFolding/importSelector.py,sha256=OY_LuUrLW5SFV6qM1tSgI2Rnfi5Bj3Fhdrkryo0WycE,392
8
- mapFolding/inlineAfunction.py,sha256=KO2snTNSGX-4urRtTOYqAZBCsBCaMfr5bo6rNZR9MPA,5102
3
+ mapFolding/beDRY.py,sha256=IhBnlo-Lg8DBaebTDAyJ7OiGUce9OFbNUNHJmlB04L0,15835
4
+ mapFolding/importSelector.py,sha256=sc9IGk8CpCNerFbuYnrroBH-itqsxjeBc4VYjiesOQo,310
9
5
  mapFolding/lovelace.py,sha256=iu7anbA_TacIAjc4EKkeBVxIJKAMdrYgvR4evzMZ1WY,15193
10
6
  mapFolding/oeis.py,sha256=_-fLGc1ybZ2eFxoiBrSmojMexeg6ROxtrLaBF2BzMn4,12144
11
- mapFolding/startHere.py,sha256=or7QhxgMls2hvP_I2eTBP5tffLrc3SMiE5Gz_Ik2aJY,4328
7
+ mapFolding/startHere.py,sha256=Bu4boZnxlx66IU7RIsBRq00JScE0DWqKLAclUMPGOSM,3892
12
8
  mapFolding/theSSOT.py,sha256=3Zty4rYWOqrwivuCaKA71R0HM4rjmvtkL_Bsn4ZhwFo,2318
13
- mapFolding/JAX/lunnanJAX.py,sha256=xMZloN47q-MVfjdYOM1hi9qR4OnLq7qALmGLMraevQs,14819
14
- mapFolding/JAX/taskJAX.py,sha256=yJNeH0rL6EhJ6ppnATHF0Zf81CDMC10bnPnimVxE1hc,20037
15
9
  mapFolding/benchmarks/benchmarking.py,sha256=HD_0NSvuabblg94ftDre6LFnXShTe8MYj3hIodW-zV0,3076
16
10
  mapFolding/reference/flattened.py,sha256=X9nvRzg7YDcpCtSDTL4YiidjshlX9rg2e6JVCY6i2u0,16547
17
11
  mapFolding/reference/hunterNumba.py,sha256=0giUyqAFzP-XKcq3Kz8wIWCK0BVFhjABVJ1s-w4Jhu0,7109
18
12
  mapFolding/reference/irvineJavaPort.py,sha256=Sj-63Z-OsGuDoEBXuxyjRrNmmyl0d7Yz_XuY7I47Oyg,4250
13
+ mapFolding/reference/jax.py,sha256=bB34dGdi3VSz4cRFbmCPn_erAmQ3FyrSED8uJ7CsES0,14961
19
14
  mapFolding/reference/lunnan.py,sha256=XEcql_gxvCCghb6Or3qwmPbn4IZUbZTaSmw_fUjRxZE,5037
20
15
  mapFolding/reference/lunnanNumpy.py,sha256=HqDgSwTOZA-G0oophOEfc4zs25Mv4yw2aoF1v8miOLk,4653
21
16
  mapFolding/reference/lunnanWhile.py,sha256=7NY2IKO5XBgol0aWWF_Fi-7oTL9pvu_z6lB0TF1uVHk,4063
22
17
  mapFolding/reference/rotatedEntryPoint.py,sha256=z0QyDQtnMvXNj5ntWzzJUQUMFm1-xHGLVhtYzwmczUI,11530
23
18
  mapFolding/reference/total_countPlus1vsPlusN.py,sha256=usenM8Yn_G1dqlPl7NKKkcnbohBZVZBXTQRm2S3_EDA,8106
19
+ mapFolding/someAssemblyRequired/inlineAfunction.py,sha256=Hxytb9xgJV_Mnh8us0mA_oKwanEQWJSj3hJc25nI9Mk,6143
20
+ mapFolding/someAssemblyRequired/jobsAndTasks.py,sha256=u2ZtZ8xlQJALqQqQ8N7uBTNDbjG4OQ9nJsJZG5rLI8o,2189
21
+ mapFolding/someAssemblyRequired/makeNuitkaSource.py,sha256=jTK34OWzm6OsgFPd2mHwETxFo2X83io0M4YiEHRgk3U,3262
22
+ mapFolding/someAssemblyRequired/makeNumbaJob.py,sha256=YZ9JzzEieQH4sMqX84VGbpOJmdBatPanfmXFZ5V1Ex4,5109
24
23
  tests/__init__.py,sha256=eg9smg-6VblOr0kisM40CpGnuDtU2JgEEWGDTFVOlW8,57
25
24
  tests/conftest.py,sha256=AWB3m_jxMlkmOmGvk2ApJEk2ro5v8gmmJDcyLwN1oow,13761
26
25
  tests/pythons_idiotic_namespace.py,sha256=oOLDBergQqqhGuRpsXUnFD-R_6AlJipNKYHw-kk_OKw,33
27
26
  tests/test_oeis.py,sha256=vxnwO-cSR68htkyMh9QMVv-lvxBo6qlwPg1Rbx4JylY,7963
28
- tests/test_other.py,sha256=amhsy7VWzpuW_slBOTFPhC7e4o4k6Yp4xweNK1VHZnc,11906
27
+ tests/test_other.py,sha256=1EtLe0te7qqdazFKvKIOHPYW_ENsqAu11nzJO0yAE_Q,12012
29
28
  tests/test_tasks.py,sha256=Nwe4iuSjwGZvsw5CXCcic7tkBxgM5JX9mrGZMDYhAwE,1785
30
- tests/test_temporary.py,sha256=4FIEc9KGRpNsgU_eh8mXG49PSPqo8WLeZEyFI4Dpy3U,1127
31
- mapFolding-0.2.4.dist-info/METADATA,sha256=w1OgxNLylmuYfEKUsSIChm_8jLtjV63_OB04n8Btjm8,6543
32
- mapFolding-0.2.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
33
- mapFolding-0.2.4.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
34
- mapFolding-0.2.4.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
35
- mapFolding-0.2.4.dist-info/RECORD,,
29
+ mapFolding-0.2.5.dist-info/METADATA,sha256=pKBorE-WQsa2LVETIUORCw-ae3cDPtUcLbE395-oVhs,6652
30
+ mapFolding-0.2.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
31
+ mapFolding-0.2.5.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
32
+ mapFolding-0.2.5.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
33
+ mapFolding-0.2.5.dist-info/RECORD,,
tests/test_other.py CHANGED
@@ -84,7 +84,7 @@ def test_countFolds_writeFoldsTotal(
84
84
  mock_countFolds = mockFoldingFunction(foldsValue, listDimensionsTestFunctionality)
85
85
 
86
86
  with unittest.mock.patch("mapFolding.babbage._countFolds", side_effect=mock_countFolds):
87
- returned = countFolds(listDimensionsTestFunctionality, writeFoldsTotal=pathWriteTarget)
87
+ returned = countFolds(listDimensionsTestFunctionality, pathishWriteFoldsTotal=pathWriteTarget)
88
88
 
89
89
  standardComparison(foldsValue, lambda: returned) # Check return value
90
90
  standardComparison(str(foldsValue), lambda: (pathTempTesting / filenameFoldsTotalExpected).read_text()) # Check file content
@@ -224,33 +224,33 @@ def parameterIterator():
224
224
  yield dict(zip(parameterKeys, combination))
225
225
 
226
226
  return generateCombinations
227
-
228
- def test_outfitCountFolds_basic(listDimensionsTestFunctionality, parameterIterator):
229
- """Basic validation of outfitCountFolds return value structure."""
230
- parameters = next(parameterIterator(listDimensionsTestFunctionality))
231
-
232
- stateInitialized = outfitCountFolds(
233
- listDimensionsTestFunctionality,
234
- **{k: v for k, v in parameters.items() if v is not None}
235
- )
236
-
237
- # Basic structure tests
238
- assert isinstance(stateInitialized, dict)
239
- assert len(stateInitialized) == 7 # 6 ndarray + 1 tuple
240
-
241
- # Check for specific keys
242
- requiredKeys = set(computationState.__annotations__.keys())
243
- assert set(stateInitialized.keys()) == requiredKeys
244
-
245
- # Check types more carefully
246
- for key, value in stateInitialized.items():
247
- if key == 'mapShape':
248
- assert isinstance(value, tuple)
249
- assert all(isinstance(dim, int) for dim in value)
250
- else:
251
- assert isinstance(value, numpy.ndarray), f"{key} should be ndarray but is {type(value)}"
252
- assert issubclass(value.dtype.type, numpy.integer), \
253
- f"{key} should have integer dtype but has {value.dtype}"
227
+ # Must mock the set cpu count to avoid errors on GitHub
228
+ # def test_outfitCountFolds_basic(listDimensionsTestFunctionality, parameterIterator):
229
+ # """Basic validation of outfitCountFolds return value structure."""
230
+ # parameters = next(parameterIterator(listDimensionsTestFunctionality))
231
+
232
+ # stateInitialized = outfitCountFolds(
233
+ # listDimensionsTestFunctionality,
234
+ # **{k: v for k, v in parameters.items() if v is not None}
235
+ # )
236
+
237
+ # # Basic structure tests
238
+ # assert isinstance(stateInitialized, dict)
239
+ # assert len(stateInitialized) == 7 # 6 ndarray + 1 tuple
240
+
241
+ # # Check for specific keys
242
+ # requiredKeys = set(computationState.__annotations__.keys())
243
+ # assert set(stateInitialized.keys()) == requiredKeys
244
+
245
+ # # Check types more carefully
246
+ # for key, value in stateInitialized.items():
247
+ # if key == 'mapShape':
248
+ # assert isinstance(value, tuple)
249
+ # assert all(isinstance(dim, int) for dim in value)
250
+ # else:
251
+ # assert isinstance(value, numpy.ndarray), f"{key} should be ndarray but is {type(value)}"
252
+ # assert issubclass(value.dtype.type, numpy.integer), \
253
+ # f"{key} should have integer dtype but has {value.dtype}"
254
254
 
255
255
  def test_pathJobDEFAULT_colab():
256
256
  """Test that pathJobDEFAULT is set correctly when running in Google Colab."""
mapFolding/JAX/taskJAX.py DELETED
@@ -1,313 +0,0 @@
1
- from mapFolding import validateListDimensions, getLeavesTotal
2
- from typing import List, Tuple
3
- import jax
4
- import jaxtyping
5
-
6
- dtypeDefault = jax.numpy.int32
7
- dtypeMaximum = jax.numpy.int32
8
-
9
- def countFolds(listDimensions: List[int]):
10
- """Calculate foldings across multiple devices using pmap"""
11
- p = validateListDimensions(listDimensions)
12
- n = getLeavesTotal(p)
13
-
14
- # Get number of devices (GPUs/TPUs)
15
- deviceCount = jax.device_count()
16
-
17
- if deviceCount > 1:
18
- # Split work across devices
19
- tasksPerDevice = (n + deviceCount - 1) // deviceCount
20
- paddedTaskCount = tasksPerDevice * deviceCount
21
-
22
- # Create padded array of task indices
23
- arrayTaskIndices = jax.numpy.arange(paddedTaskCount, dtype=dtypeDefault)
24
- arrayTaskIndices = arrayTaskIndices.reshape((deviceCount, tasksPerDevice))
25
-
26
- # Create pmapped function
27
- parallelFoldingsTask = jax.pmap(lambda x: jax.vmap(lambda y: foldingsTask(tuple(p), y))(x))
28
-
29
- # Run computation across devices
30
- arrayResults = parallelFoldingsTask(arrayTaskIndices)
31
-
32
- # Sum valid results (ignore padding)
33
- return jax.numpy.sum(arrayResults[:, :min(tasksPerDevice, n - tasksPerDevice * (deviceCount-1))])
34
- else:
35
- # Fall back to sequential execution if no multiple devices available
36
- arrayTaskIndices = jax.numpy.arange(n, dtype=dtypeDefault)
37
- batchedFoldingsTask = jax.vmap(lambda x: foldingsTask(tuple(p), x))
38
- return jax.numpy.sum(batchedFoldingsTask(arrayTaskIndices))
39
-
40
- def foldingsTask(p, taskIndex) -> jaxtyping.UInt32:
41
- arrayDimensions = jax.numpy.asarray(p, dtype=dtypeDefault)
42
- leavesTotal = jax.numpy.prod(arrayDimensions)
43
- dimensionsTotal = jax.numpy.size(arrayDimensions)
44
-
45
- """How to build a leaf connection graph, also called a "Cartesian Product Decomposition"
46
- or a "Dimensional Product Mapping", with sentinels:
47
- Step 1: find the cumulative product of the map's dimensions"""
48
- cumulativeProduct = jax.numpy.ones(dimensionsTotal + 1, dtype=dtypeDefault)
49
- cumulativeProduct = cumulativeProduct.at[1:].set(jax.numpy.cumprod(arrayDimensions))
50
-
51
- """Step 2: for each dimension, create a coordinate system """
52
- """coordinateSystem[dimension1ndex][leaf1ndex] holds the dimension1ndex-th coordinate of leaf leaf1ndex"""
53
- coordinateSystem = jax.numpy.zeros((dimensionsTotal + 1, leavesTotal + 1), dtype=dtypeDefault)
54
-
55
- # Create mesh of indices for vectorized computation
56
- dimension1ndices, leaf1ndices = jax.numpy.meshgrid(
57
- jax.numpy.arange(1, dimensionsTotal + 1),
58
- jax.numpy.arange(1, leavesTotal + 1),
59
- indexing='ij'
60
- )
61
-
62
- # Compute all coordinates at once using broadcasting
63
- coordinateSystem = coordinateSystem.at[1:, 1:].set(
64
- ((leaf1ndices - 1) // cumulativeProduct.at[dimension1ndices - 1].get()) %
65
- arrayDimensions.at[dimension1ndices - 1].get() + 1
66
- )
67
- del dimension1ndices, leaf1ndices
68
-
69
- """Step 3: create a huge empty connection graph"""
70
- connectionGraph = jax.numpy.zeros((dimensionsTotal + 1, leavesTotal + 1, leavesTotal + 1), dtype=dtypeDefault)
71
-
72
- # Create 3D mesh of indices for vectorized computation
73
- dimension1ndices, activeLeaf1ndices, connectee1ndices = jax.numpy.meshgrid(
74
- jax.numpy.arange(1, dimensionsTotal + 1),
75
- jax.numpy.arange(1, leavesTotal + 1),
76
- jax.numpy.arange(1, leavesTotal + 1),
77
- indexing='ij'
78
- )
79
-
80
- # Create masks for valid indices
81
- maskActiveConnectee = connectee1ndices <= activeLeaf1ndices
82
-
83
- # Calculate coordinate parity comparison
84
- coordsParity = (coordinateSystem.at[dimension1ndices, activeLeaf1ndices].get() & 1) == \
85
- (coordinateSystem.at[dimension1ndices, connectee1ndices].get() & 1)
86
-
87
- # Compute distance conditions
88
- isFirstCoord = coordinateSystem.at[dimension1ndices, connectee1ndices].get() == 1
89
- isLastCoord = coordinateSystem.at[dimension1ndices, connectee1ndices].get() == \
90
- arrayDimensions.at[dimension1ndices - 1].get()
91
- exceedsActive = connectee1ndices + cumulativeProduct.at[dimension1ndices - 1].get() > activeLeaf1ndices
92
-
93
- # Compute connection values for even and odd parities
94
- evenParityValues = jax.numpy.where(
95
- isFirstCoord,
96
- connectee1ndices,
97
- connectee1ndices - cumulativeProduct.at[dimension1ndices - 1].get()
98
- )
99
-
100
- oddParityValues = jax.numpy.where(
101
- jax.numpy.logical_or(isLastCoord, exceedsActive),
102
- connectee1ndices,
103
- connectee1ndices + cumulativeProduct.at[dimension1ndices - 1].get()
104
- )
105
-
106
- # Combine based on parity and valid indices
107
- connectionValues = jax.numpy.where(
108
- coordsParity,
109
- evenParityValues,
110
- oddParityValues
111
- )
112
-
113
- # Update only valid connections
114
- connectionGraph = connectionGraph.at[dimension1ndices, activeLeaf1ndices, connectee1ndices].set(
115
- jax.numpy.where(maskActiveConnectee, connectionValues, 0)
116
- )
117
-
118
- def doNothing(argument):
119
- return argument
120
-
121
- def while_activeLeaf1ndex_greaterThan_0(comparisonValues: Tuple):
122
- comparand = comparisonValues[6]
123
- return comparand > 0
124
-
125
- def countFoldings(allValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
126
- _0, leafBelow, _2, _3, _4, _5, activeLeaf1ndex, _7 = allValues
127
-
128
- sentinel = leafBelow.at[0].get().astype(jax.numpy.int32)
129
-
130
- allValues = jax.lax.cond(findGapsCondition(sentinel, activeLeaf1ndex),
131
- lambda argumentX: dao(findGapsDo(argumentX)),
132
- lambda argumentY: jax.lax.cond(incrementCondition(sentinel, activeLeaf1ndex), lambda argumentZ: dao(incrementDo(argumentZ)), dao, argumentY),
133
- allValues)
134
-
135
- return allValues
136
-
137
- def findGapsCondition(leafBelowSentinel, activeLeafNumber):
138
- return jax.numpy.logical_or(jax.numpy.logical_and(leafBelowSentinel == 1, activeLeafNumber <= leavesTotal), activeLeafNumber <= 1)
139
-
140
- def findGapsDo(allValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
141
- def for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1(comparisonValues: Tuple):
142
- return comparisonValues[-1] <= dimensionsTotal
143
-
144
- def for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1_do(for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
145
- def ifLeafIsUnconstrainedCondition(comparand):
146
- return jax.numpy.equal(connectionGraph[comparand, activeLeaf1ndex, activeLeaf1ndex], activeLeaf1ndex)
147
-
148
- def ifLeafIsUnconstrainedDo(unconstrainedValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
149
- unconstrained_unconstrainedLeaf = unconstrainedValues[3]
150
- unconstrained_unconstrainedLeaf = 1 + unconstrained_unconstrainedLeaf
151
- return (unconstrainedValues[0], unconstrainedValues[1], unconstrainedValues[2], unconstrained_unconstrainedLeaf)
152
-
153
- def ifLeafIsUnconstrainedElse(unconstrainedValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
154
- def while_leaf1ndexConnectee_notEquals_activeLeaf1ndex(comparisonValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
155
- return comparisonValues[-1] != activeLeaf1ndex
156
-
157
- def countGaps(countGapsDoValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
158
- # if taskDivisions == False or activeLeaf1ndex != leavesTotal or leaf1ndexConnectee % leavesTotal == taskIndex:
159
- def taskDivisionComparison():
160
- return jax.numpy.logical_or(activeLeaf1ndex != leavesTotal, jax.numpy.equal(countGapsLeaf1ndexConnectee % leavesTotal, taskIndex))
161
- # return taskDivisions == False or jax.numpy.logical_or(activeLeaf1ndex != leavesTotal, jax.numpy.equal(countGapsLeaf1ndexConnectee % leavesTotal, taskIndex))
162
-
163
- def taskDivisionDo(taskDivisionDoValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32]):
164
- taskDivisionCountDimensionsGapped, taskDivisionPotentialGaps, taskDivisionGap1ndexLowerBound = taskDivisionDoValues
165
-
166
- taskDivisionPotentialGaps = taskDivisionPotentialGaps.at[taskDivisionGap1ndexLowerBound].set(countGapsLeaf1ndexConnectee)
167
- taskDivisionGap1ndexLowerBound = jax.numpy.where(
168
- jax.numpy.equal(taskDivisionCountDimensionsGapped.at[countGapsLeaf1ndexConnectee].get(), 0), taskDivisionGap1ndexLowerBound + 1, taskDivisionGap1ndexLowerBound)
169
- taskDivisionCountDimensionsGapped = taskDivisionCountDimensionsGapped.at[countGapsLeaf1ndexConnectee].add(1)
170
-
171
- return (taskDivisionCountDimensionsGapped, taskDivisionPotentialGaps, taskDivisionGap1ndexLowerBound)
172
-
173
- countGapsLeaf1ndexConnectee = countGapsDoValues[3]
174
- taskDivisionValues = (countGapsDoValues[0], countGapsDoValues[1], countGapsDoValues[2])
175
- taskDivisionValues = jax.lax.cond(taskDivisionComparison(), taskDivisionDo, doNothing, taskDivisionValues)
176
-
177
- countGapsLeaf1ndexConnectee = connectionGraph.at[dimensionNumber, activeLeaf1ndex, leafBelow.at[countGapsLeaf1ndexConnectee].get()].get().astype(jax.numpy.int32)
178
-
179
- return (taskDivisionValues[0], taskDivisionValues[1], taskDivisionValues[2], countGapsLeaf1ndexConnectee)
180
-
181
- unconstrained_countDimensionsGapped, unconstrained_gapsWhere, unconstrained_gap1ndexCeiling, unconstrained_unconstrainedLeaf = unconstrainedValues
182
-
183
- leaf1ndexConnectee = connectionGraph.at[dimensionNumber, activeLeaf1ndex, activeLeaf1ndex].get().astype(jax.numpy.int32)
184
-
185
- countGapsValues = (unconstrained_countDimensionsGapped, unconstrained_gapsWhere, unconstrained_gap1ndexCeiling, leaf1ndexConnectee)
186
- countGapsValues = jax.lax.while_loop(while_leaf1ndexConnectee_notEquals_activeLeaf1ndex, countGaps, countGapsValues)
187
- unconstrained_countDimensionsGapped, unconstrained_gapsWhere, unconstrained_gap1ndexCeiling, leaf1ndexConnectee = countGapsValues
188
-
189
- return (unconstrained_countDimensionsGapped, unconstrained_gapsWhere, unconstrained_gap1ndexCeiling, unconstrained_unconstrainedLeaf)
190
-
191
- dimensions_countDimensionsGapped, dimensions_gapsWhere, dimensions_gap1ndexCeiling, dimensions_unconstrainedLeaf, dimensionNumber = for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values
192
-
193
- ifLeafIsUnconstrainedValues = (dimensions_countDimensionsGapped, dimensions_gapsWhere, dimensions_gap1ndexCeiling, dimensions_unconstrainedLeaf)
194
- ifLeafIsUnconstrainedValues = jax.lax.cond(ifLeafIsUnconstrainedCondition(dimensionNumber), ifLeafIsUnconstrainedDo, ifLeafIsUnconstrainedElse, ifLeafIsUnconstrainedValues)
195
- dimensions_countDimensionsGapped, dimensions_gapsWhere, dimensions_gap1ndexCeiling, dimensions_unconstrainedLeaf = ifLeafIsUnconstrainedValues
196
-
197
- dimensionNumber = 1 + dimensionNumber
198
- return (dimensions_countDimensionsGapped, dimensions_gapsWhere, dimensions_gap1ndexCeiling, dimensions_unconstrainedLeaf, dimensionNumber)
199
-
200
- def almostUselessCondition(comparand):
201
- return comparand == dimensionsTotal
202
-
203
- def almostUselessConditionDo(for_leaf1ndex_in_range_activeLeaf1ndexValues: Tuple[jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
204
- def for_leaf1ndex_in_range_activeLeaf1ndex(comparisonValues):
205
- return comparisonValues[-1] < activeLeaf1ndex
206
-
207
- def for_leaf1ndex_in_range_activeLeaf1ndex_do(for_leaf1ndex_in_range_activeLeaf1ndexValues: Tuple[jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
208
- leafInRangePotentialGaps, gapNumberLowerBound, leafNumber = for_leaf1ndex_in_range_activeLeaf1ndexValues
209
- leafInRangePotentialGaps = leafInRangePotentialGaps.at[gapNumberLowerBound].set(leafNumber)
210
- gapNumberLowerBound = 1 + gapNumberLowerBound
211
- leafNumber = 1 + leafNumber
212
- return (leafInRangePotentialGaps, gapNumberLowerBound, leafNumber)
213
- return jax.lax.while_loop(for_leaf1ndex_in_range_activeLeaf1ndex, for_leaf1ndex_in_range_activeLeaf1ndex_do, for_leaf1ndex_in_range_activeLeaf1ndexValues)
214
-
215
- def for_range_from_activeGap1ndex_to_gap1ndexCeiling(comparisonValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
216
- return comparisonValues[-1] < gap1ndexCeiling
217
-
218
- def miniGapDo(gapToGapValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
219
- gapToGapCountDimensionsGapped, gapToGapPotentialGaps, activeGapNumber, index = gapToGapValues
220
- gapToGapPotentialGaps = gapToGapPotentialGaps.at[activeGapNumber].set(gapToGapPotentialGaps.at[index].get())
221
- activeGapNumber = jax.numpy.where(jax.numpy.equal(gapToGapCountDimensionsGapped.at[gapToGapPotentialGaps.at[index].get()].get(), dimensionsTotal - unconstrainedLeaf), activeGapNumber + 1, activeGapNumber).astype(jax.numpy.int32)
222
- gapToGapCountDimensionsGapped = gapToGapCountDimensionsGapped.at[gapToGapPotentialGaps.at[index].get()].set(0)
223
- index = 1 + index
224
- return (gapToGapCountDimensionsGapped, gapToGapPotentialGaps, activeGapNumber, index)
225
-
226
- _0, leafBelow, countDimensionsGapped, gapRangeStart, gapsWhere, _5, activeLeaf1ndex, activeGap1ndex = allValues
227
-
228
- unconstrainedLeaf = jax.numpy.int32(0)
229
- dimension1ndex = jax.numpy.int32(1)
230
- gap1ndexCeiling = gapRangeStart.at[activeLeaf1ndex - 1].get().astype(jax.numpy.int32)
231
- activeGap1ndex = gap1ndexCeiling
232
- for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values = (countDimensionsGapped, gapsWhere, gap1ndexCeiling, unconstrainedLeaf, dimension1ndex)
233
- for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values = jax.lax.while_loop(for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1, for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1_do, for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values)
234
- countDimensionsGapped, gapsWhere, gap1ndexCeiling, unconstrainedLeaf, dimension1ndex = for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values
235
- del dimension1ndex
236
-
237
- leaf1ndex = jax.numpy.int32(0)
238
- for_leaf1ndex_in_range_activeLeaf1ndexValues = (gapsWhere, gap1ndexCeiling, leaf1ndex)
239
- for_leaf1ndex_in_range_activeLeaf1ndexValues = jax.lax.cond(almostUselessCondition(unconstrainedLeaf), almostUselessConditionDo, doNothing, for_leaf1ndex_in_range_activeLeaf1ndexValues)
240
- gapsWhere, gap1ndexCeiling, leaf1ndex = for_leaf1ndex_in_range_activeLeaf1ndexValues
241
- del leaf1ndex
242
-
243
- indexMiniGap = activeGap1ndex
244
- miniGapValues = (countDimensionsGapped, gapsWhere, activeGap1ndex, indexMiniGap)
245
- miniGapValues = jax.lax.while_loop(for_range_from_activeGap1ndex_to_gap1ndexCeiling, miniGapDo, miniGapValues)
246
- countDimensionsGapped, gapsWhere, activeGap1ndex, indexMiniGap = miniGapValues
247
- del indexMiniGap
248
-
249
- return (allValues[0], leafBelow, countDimensionsGapped, gapRangeStart, gapsWhere, allValues[5], activeLeaf1ndex, activeGap1ndex)
250
-
251
- def incrementCondition(leafBelowSentinel, activeLeafNumber):
252
- return jax.numpy.logical_and(activeLeafNumber > leavesTotal, leafBelowSentinel == 1)
253
-
254
- def incrementDo(allValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
255
- foldingsSubTotal = allValues[5]
256
- foldingsSubTotal = leavesTotal + foldingsSubTotal
257
- return (allValues[0], allValues[1], allValues[2], allValues[3], allValues[4], foldingsSubTotal, allValues[6], allValues[7])
258
-
259
- def dao(allValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
260
- def whileBacktrackingCondition(backtrackingValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32]):
261
- comparand = backtrackingValues[2]
262
- return jax.numpy.logical_and(comparand > 0, jax.numpy.equal(activeGap1ndex, gapRangeStart.at[comparand - 1].get()))
263
-
264
- def whileBacktrackingDo(backtrackingValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32]):
265
- backtrackAbove, backtrackBelow, activeLeafNumber = backtrackingValues
266
-
267
- activeLeafNumber = activeLeafNumber - 1
268
- backtrackBelow = backtrackBelow.at[backtrackAbove.at[activeLeafNumber].get()].set(backtrackBelow.at[activeLeafNumber].get())
269
- backtrackAbove = backtrackAbove.at[backtrackBelow.at[activeLeafNumber].get()].set(backtrackAbove.at[activeLeafNumber].get())
270
-
271
- return (backtrackAbove, backtrackBelow, activeLeafNumber)
272
-
273
- def if_activeLeaf1ndex_greaterThan_0(activeLeafNumber):
274
- return activeLeafNumber > 0
275
-
276
- def if_activeLeaf1ndex_greaterThan_0_do(leafPlacementValues: Tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
277
- placeLeafAbove, placeLeafBelow, placeGapRangeStart, activeLeafNumber, activeGapNumber = leafPlacementValues
278
- activeGapNumber = activeGapNumber - 1
279
- placeLeafAbove = placeLeafAbove.at[activeLeafNumber].set(gapsWhere.at[activeGapNumber].get())
280
- placeLeafBelow = placeLeafBelow.at[activeLeafNumber].set(placeLeafBelow.at[placeLeafAbove.at[activeLeafNumber].get()].get())
281
- placeLeafBelow = placeLeafBelow.at[placeLeafAbove.at[activeLeafNumber].get()].set(activeLeafNumber)
282
- placeLeafAbove = placeLeafAbove.at[placeLeafBelow.at[activeLeafNumber].get()].set(activeLeafNumber)
283
- placeGapRangeStart = placeGapRangeStart.at[activeLeafNumber].set(activeGapNumber)
284
-
285
- activeLeafNumber = 1 + activeLeafNumber
286
- return (placeLeafAbove, placeLeafBelow, placeGapRangeStart, activeLeafNumber, activeGapNumber)
287
-
288
- leafAbove, leafBelow, _2, gapRangeStart, gapsWhere, _5, activeLeaf1ndex, activeGap1ndex = allValues
289
-
290
- whileBacktrackingValues = (leafAbove, leafBelow, activeLeaf1ndex)
291
- whileBacktrackingValues = jax.lax.while_loop(whileBacktrackingCondition, whileBacktrackingDo, whileBacktrackingValues)
292
- leafAbove, leafBelow, activeLeaf1ndex = whileBacktrackingValues
293
-
294
- if_activeLeaf1ndex_greaterThan_0_values = (leafAbove, leafBelow, gapRangeStart, activeLeaf1ndex, activeGap1ndex)
295
- if_activeLeaf1ndex_greaterThan_0_values = jax.lax.cond(if_activeLeaf1ndex_greaterThan_0(activeLeaf1ndex), if_activeLeaf1ndex_greaterThan_0_do, doNothing, if_activeLeaf1ndex_greaterThan_0_values)
296
- leafAbove, leafBelow, gapRangeStart, activeLeaf1ndex, activeGap1ndex = if_activeLeaf1ndex_greaterThan_0_values
297
-
298
- return (leafAbove, leafBelow, allValues[2], gapRangeStart, gapsWhere, allValues[5], activeLeaf1ndex, activeGap1ndex)
299
-
300
- # Dynamic values
301
- A = jax.numpy.zeros(leavesTotal + 1, dtype=dtypeDefault)
302
- B = jax.numpy.zeros(leavesTotal + 1, dtype=dtypeDefault)
303
- count = jax.numpy.zeros(leavesTotal + 1, dtype=dtypeDefault)
304
- gapter = jax.numpy.zeros(leavesTotal + 1, dtype=dtypeDefault)
305
- gap = jax.numpy.zeros(leavesTotal * leavesTotal + 1, dtype=dtypeMaximum)
306
-
307
- foldingsSubTotal = jax.numpy.int32(0)
308
- l = jax.numpy.int32(1)
309
- g = jax.numpy.int32(0)
310
-
311
- foldingsValues = (A, B, count, gapter, gap, foldingsSubTotal, l, g)
312
- foldingsValues = jax.lax.while_loop(while_activeLeaf1ndex_greaterThan_0, countFoldings, foldingsValues)
313
- return foldingsValues[5]
@@ -1,44 +0,0 @@
1
- import numba
2
-
3
- @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)
4
- def countInitialize(connectionGraph, gapsWhere, my, the, track):
5
- while my[6] > 0:
6
- if my[6] <= 1 or track[1, 0] == 1:
7
- my[1] = 0
8
- my[3] = track[3, my[6] - 1]
9
- my[0] = 1
10
- while my[0] <= the[0]:
11
- if connectionGraph[my[0], my[6], my[6]] == my[6]:
12
- my[1] += 1
13
- else:
14
- my[7] = connectionGraph[my[0], my[6], my[6]]
15
- while my[7] != my[6]:
16
- gapsWhere[my[3]] = my[7]
17
- if track[2, my[7]] == 0:
18
- my[3] += 1
19
- track[2, my[7]] += 1
20
- my[7] = connectionGraph[my[0], my[6], track[1, my[7]]]
21
- my[0] += 1
22
- if my[1] == the[0]:
23
- my[4] = 0
24
- while my[4] < my[6]:
25
- gapsWhere[my[3]] = my[4]
26
- my[3] += 1
27
- my[4] += 1
28
- my[5] = my[2]
29
- while my[5] < my[3]:
30
- gapsWhere[my[2]] = gapsWhere[my[5]]
31
- if track[2, gapsWhere[my[5]]] == the[0] - my[1]:
32
- my[2] += 1
33
- track[2, gapsWhere[my[5]]] = 0
34
- my[5] += 1
35
- if my[6] > 0:
36
- my[2] -= 1
37
- track[0, my[6]] = gapsWhere[my[2]]
38
- track[1, my[6]] = track[1, track[0, my[6]]]
39
- track[1, track[0, my[6]]] = my[6]
40
- track[0, track[1, my[6]]] = my[6]
41
- track[3, my[6]] = my[2]
42
- my[6] += 1
43
- if my[2] > 0:
44
- return
@@ -1,49 +0,0 @@
1
- import numba
2
-
3
- @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)
4
- def countParallel(connectionGraph, foldsSubTotals, gapsWherePARALLEL, myPARALLEL, the, trackPARALLEL):
5
- for indexSherpa in numba.prange(the[2]):
6
- gapsWhere = gapsWherePARALLEL.copy()
7
- my = myPARALLEL.copy()
8
- my[8] = indexSherpa
9
- track = trackPARALLEL.copy()
10
- while my[6] > 0:
11
- if my[6] <= 1 or track[1, 0] == 1:
12
- if my[6] > the[1]:
13
- foldsSubTotals[my[8]] += the[1]
14
- else:
15
- my[1] = 0
16
- my[3] = track[3, my[6] - 1]
17
- my[0] = 1
18
- while my[0] <= the[0]:
19
- if connectionGraph[my[0], my[6], my[6]] == my[6]:
20
- my[1] += 1
21
- else:
22
- my[7] = connectionGraph[my[0], my[6], my[6]]
23
- while my[7] != my[6]:
24
- if my[6] != the[2] or my[7] % the[2] == my[8]:
25
- gapsWhere[my[3]] = my[7]
26
- if track[2, my[7]] == 0:
27
- my[3] += 1
28
- track[2, my[7]] += 1
29
- my[7] = connectionGraph[my[0], my[6], track[1, my[7]]]
30
- my[0] += 1
31
- my[5] = my[2]
32
- while my[5] < my[3]:
33
- gapsWhere[my[2]] = gapsWhere[my[5]]
34
- if track[2, gapsWhere[my[5]]] == the[0] - my[1]:
35
- my[2] += 1
36
- track[2, gapsWhere[my[5]]] = 0
37
- my[5] += 1
38
- while my[6] > 0 and my[2] == track[3, my[6] - 1]:
39
- my[6] -= 1
40
- track[1, track[0, my[6]]] = track[1, my[6]]
41
- track[0, track[1, my[6]]] = track[0, my[6]]
42
- if my[6] > 0:
43
- my[2] -= 1
44
- track[0, my[6]] = gapsWhere[my[2]]
45
- track[1, my[6]] = track[1, track[0, my[6]]]
46
- track[1, track[0, my[6]]] = my[6]
47
- track[0, track[1, my[6]]] = my[6]
48
- track[3, my[6]] = my[2]
49
- my[6] += 1
@@ -1,43 +0,0 @@
1
- import numba
2
-
3
- @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)
4
- def countSequential(connectionGraph, foldsSubTotals, gapsWhere, my, the, track):
5
- while my[6] > 0:
6
- if my[6] <= 1 or track[1, 0] == 1:
7
- if my[6] > the[1]:
8
- foldsSubTotals[my[8]] += the[1]
9
- else:
10
- my[1] = 0
11
- my[3] = track[3, my[6] - 1]
12
- my[0] = 1
13
- while my[0] <= the[0]:
14
- if connectionGraph[my[0], my[6], my[6]] == my[6]:
15
- my[1] += 1
16
- else:
17
- my[7] = connectionGraph[my[0], my[6], my[6]]
18
- while my[7] != my[6]:
19
- gapsWhere[my[3]] = my[7]
20
- if track[2, my[7]] == 0:
21
- my[3] += 1
22
- track[2, my[7]] += 1
23
- my[7] = connectionGraph[my[0], my[6], track[1, my[7]]]
24
- my[0] += 1
25
- my[5] = my[2]
26
- while my[5] < my[3]:
27
- gapsWhere[my[2]] = gapsWhere[my[5]]
28
- if track[2, gapsWhere[my[5]]] == the[0] - my[1]:
29
- my[2] += 1
30
- track[2, gapsWhere[my[5]]] = 0
31
- my[5] += 1
32
- while my[6] > 0 and my[2] == track[3, my[6] - 1]:
33
- my[6] -= 1
34
- track[1, track[0, my[6]]] = track[1, my[6]]
35
- track[0, track[1, my[6]]] = track[0, my[6]]
36
- if my[6] > 0:
37
- my[2] -= 1
38
- track[0, my[6]] = gapsWhere[my[2]]
39
- track[1, my[6]] = track[1, track[0, my[6]]]
40
- track[1, track[0, my[6]]] = my[6]
41
- track[0, track[1, my[6]]] = my[6]
42
- track[3, my[6]] = my[2]
43
- my[6] += 1
tests/test_temporary.py DELETED
@@ -1,25 +0,0 @@
1
- from tests.conftest import *
2
- from typing import Dict, List, Tuple
3
- import importlib
4
- import pytest
5
-
6
- @pytest.fixture(scope="session", autouse=True)
7
- def runSecondSetAfterAll(request: pytest.FixtureRequest):
8
- """Run after all other tests complete."""
9
- def toggleAndRerun():
10
- import mapFolding.importSelector
11
- import mapFolding.babbage
12
- mapFolding.importSelector.useLovelace = not mapFolding.importSelector.useLovelace
13
- importlib.reload(mapFolding.importSelector)
14
- importlib.reload(mapFolding.babbage)
15
-
16
- request.addfinalizer(toggleAndRerun)
17
-
18
- @pytest.mark.order(after="runSecondSetAfterAll")
19
- def test_myabilitytodealwithbs(oeisID: str):
20
- for n in settingsOEIS[oeisID]['valuesTestValidation']:
21
- standardComparison(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
22
-
23
- @pytest.mark.order(after="runSecondSetAfterAll")
24
- def test_eff_em_el(listDimensionsTest_countFolds: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int]) -> None:
25
- standardComparison(foldsTotalKnown[tuple(listDimensionsTest_countFolds)], countFolds, listDimensionsTest_countFolds, None, 'maximum')