mapFolding 0.2.4__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mapfolding-0.2.4 → mapfolding-0.2.5}/PKG-INFO +8 -8
- {mapfolding-0.2.4 → mapfolding-0.2.5}/README.md +6 -1
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/__init__.py +1 -1
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/beDRY.py +47 -3
- mapfolding-0.2.5/mapFolding/importSelector.py +7 -0
- mapfolding-0.2.4/mapFolding/JAX/lunnanJAX.py → mapfolding-0.2.5/mapFolding/reference/jax.py +2 -0
- {mapfolding-0.2.4/mapFolding → mapfolding-0.2.5/mapFolding/someAssemblyRequired}/inlineAfunction.py +59 -31
- mapfolding-0.2.5/mapFolding/someAssemblyRequired/jobsAndTasks.py +47 -0
- mapfolding-0.2.5/mapFolding/someAssemblyRequired/makeNuitkaSource.py +99 -0
- mapfolding-0.2.5/mapFolding/someAssemblyRequired/makeNumbaJob.py +121 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/startHere.py +8 -17
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding.egg-info/PKG-INFO +8 -8
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding.egg-info/SOURCES.txt +6 -8
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding.egg-info/requires.txt +0 -6
- {mapfolding-0.2.4 → mapfolding-0.2.5}/pyproject.toml +5 -6
- {mapfolding-0.2.4 → mapfolding-0.2.5}/tests/test_other.py +28 -28
- mapfolding-0.2.4/mapFolding/JAX/taskJAX.py +0 -313
- mapfolding-0.2.4/mapFolding/countInitialize.py +0 -44
- mapfolding-0.2.4/mapFolding/countParallel.py +0 -49
- mapfolding-0.2.4/mapFolding/countSequential.py +0 -43
- mapfolding-0.2.4/mapFolding/importSelector.py +0 -12
- mapfolding-0.2.4/tests/test_temporary.py +0 -25
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/babbage.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/benchmarks/benchmarking.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/lovelace.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/oeis.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/flattened.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/hunterNumba.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/irvineJavaPort.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/lunnan.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/lunnanNumpy.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/lunnanWhile.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/rotatedEntryPoint.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding/theSSOT.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding.egg-info/dependency_links.txt +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding.egg-info/entry_points.txt +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/mapFolding.egg-info/top_level.txt +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/setup.cfg +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/tests/__init__.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/tests/conftest.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/tests/pythons_idiotic_namespace.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/tests/test_oeis.py +0 -0
- {mapfolding-0.2.4 → mapfolding-0.2.5}/tests/test_tasks.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: mapFolding
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary:
|
|
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
|
-
[](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml) [](https://pypi.org/project/mapFolding/) [](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml) [](https://youtu.be/g6f_miE91mk&t=4)   
|
|
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
|
+
[](https://HunterThinks.com/support)
|
|
135
|
+
[](https://www.youtube.com/@HunterHogan)
|
|
@@ -14,7 +14,7 @@ The directory [mapFolding/reference](https://github.com/hunterhogan/mapFolding/b
|
|
|
14
14
|
- [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
|
|
15
15
|
- miscellaneous notes.
|
|
16
16
|
|
|
17
|
-
[](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml) [](https://pypi.org/project/mapFolding/) [](https://github.com/hunterhogan/mapFolding/actions/workflows/unittests.yml) [](https://youtu.be/g6f_miE91mk&t=4)   
|
|
18
18
|
|
|
19
19
|
## Simple, easy usage based on OEIS IDs
|
|
20
20
|
|
|
@@ -106,3 +106,8 @@ In [`foldings.txt`](https://github.com/hunterhogan/mapFolding/blob/main/mapFoldi
|
|
|
106
106
|
```sh
|
|
107
107
|
pip install mapFolding
|
|
108
108
|
```
|
|
109
|
+
|
|
110
|
+
## My recovery
|
|
111
|
+
|
|
112
|
+
[](https://HunterThinks.com/support)
|
|
113
|
+
[](https://www.youtube.com/@HunterHogan)
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -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
|
{mapfolding-0.2.4/mapFolding → mapfolding-0.2.5/mapFolding/someAssemblyRequired}/inlineAfunction.py
RENAMED
|
@@ -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
|
-
|
|
6
|
-
|
|
7
|
-
for
|
|
8
|
-
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
105
|
-
importStatements =
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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)
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
from mapFolding import outfitCountFolds,
|
|
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],
|
|
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
|
-
|
|
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
|
|
41
|
-
pathFilenameFoldsTotal =
|
|
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
|
-
|
|
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
|