mapFolding 0.2.6__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {mapFolding-0.2.6.dist-info → mapFolding-0.3.0.dist-info}/METADATA +23 -7
  2. mapFolding-0.3.0.dist-info/RECORD +20 -0
  3. mapFolding-0.3.0.dist-info/top_level.txt +3 -0
  4. someAssemblyRequired/__init__.py +3 -0
  5. someAssemblyRequired/countInitialize.py +45 -0
  6. someAssemblyRequired/countParallel.py +52 -0
  7. someAssemblyRequired/countSequential.py +59 -0
  8. mapFolding/someAssemblyRequired/inlineAfunction.py → someAssemblyRequired/synthesizeModules.py +76 -41
  9. mapFolding/__init__.py +0 -12
  10. mapFolding/babbage.py +0 -35
  11. mapFolding/beDRY.py +0 -319
  12. mapFolding/importSelector.py +0 -7
  13. mapFolding/lovelace.py +0 -213
  14. mapFolding/oeis.py +0 -323
  15. mapFolding/someAssemblyRequired/jobsAndTasks.py +0 -47
  16. mapFolding/someAssemblyRequired/makeNuitkaSource.py +0 -99
  17. mapFolding/someAssemblyRequired/makeNumbaJob.py +0 -144
  18. mapFolding/startHere.py +0 -50
  19. mapFolding/theSSOT.py +0 -76
  20. mapFolding-0.2.6.dist-info/RECORD +0 -33
  21. mapFolding-0.2.6.dist-info/top_level.txt +0 -2
  22. tests/__init__.py +0 -1
  23. tests/conftest.py +0 -343
  24. tests/pythons_idiotic_namespace.py +0 -1
  25. tests/test_oeis.py +0 -194
  26. tests/test_other.py +0 -282
  27. tests/test_tasks.py +0 -31
  28. {mapFolding/benchmarks → benchmarks}/benchmarking.py +0 -0
  29. {mapFolding-0.2.6.dist-info → mapFolding-0.3.0.dist-info}/WHEEL +0 -0
  30. {mapFolding-0.2.6.dist-info → mapFolding-0.3.0.dist-info}/entry_points.txt +0 -0
  31. {mapFolding/reference → reference}/flattened.py +0 -0
  32. {mapFolding/reference → reference}/hunterNumba.py +0 -0
  33. {mapFolding/reference → reference}/irvineJavaPort.py +0 -0
  34. {mapFolding/reference → reference}/jax.py +0 -0
  35. {mapFolding/reference → reference}/lunnan.py +0 -0
  36. {mapFolding/reference → reference}/lunnanNumpy.py +0 -0
  37. {mapFolding/reference → reference}/lunnanWhile.py +0 -0
  38. {mapFolding/reference → reference}/rotatedEntryPoint.py +0 -0
  39. {mapFolding/reference → reference}/total_countPlus1vsPlusN.py +0 -0
mapFolding/oeis.py DELETED
@@ -1,323 +0,0 @@
1
- """Everything implementing the The Online Encyclopedia of Integer Sequences (OEIS);
2
- _only_ things that implement _only_ the OEIS."""
3
- from datetime import datetime, timedelta
4
- from mapFolding import countFolds
5
- from typing import TYPE_CHECKING, List, Callable, Dict, Final
6
- import pathlib
7
- import random
8
- import sys
9
- import time
10
- import urllib.request
11
- import urllib.response
12
-
13
- if TYPE_CHECKING:
14
- from typing import TypedDict
15
- else:
16
- TypedDict = dict
17
-
18
- """
19
- Section: make `settingsOEIS`"""
20
- class SettingsOEIS(TypedDict):
21
- # I would prefer to load description dynamically from OEIS, but it's a pita for me
22
- # to learn how to efficiently implement right now.
23
- description: str
24
- getDimensions: Callable[[int], List[int]]
25
- valuesBenchmark: List[int]
26
- valuesKnown: Dict[int, int]
27
- valuesTestValidation: List[int]
28
- valueUnknown: int
29
-
30
- settingsOEIShardcodedValues = {
31
- 'A001415': {
32
- 'description': 'Number of ways of folding a 2 X n strip of stamps.',
33
- 'getDimensions': lambda n: sorted([2, n]),
34
- 'valuesBenchmark': [14],
35
- 'valuesTestValidation': [0, 1, random.randint(2, 9)],
36
- },
37
- 'A001416': {
38
- 'description': 'Number of ways of folding a 3 X n strip of stamps.',
39
- 'getDimensions': lambda n: sorted([3, n]),
40
- 'valuesBenchmark': [9],
41
- 'valuesTestValidation': [0, 1, random.randint(2, 6)],
42
- },
43
- 'A001417': {
44
- 'description': 'Number of ways of folding a 2 X 2 X ... X 2 n-dimensional map.',
45
- 'getDimensions': lambda n: [2] * n,
46
- 'valuesBenchmark': [6],
47
- 'valuesTestValidation': [0, 1, random.randint(2, 4)],
48
- },
49
- 'A195646': {
50
- 'description': 'Number of ways of folding a 3 X 3 X ... X 3 n-dimensional map.',
51
- 'getDimensions': lambda n: [3] * n,
52
- 'valuesBenchmark': [3],
53
- 'valuesTestValidation': [0, 1, 2],
54
- },
55
- 'A001418': {
56
- 'description': 'Number of ways of folding an n X n sheet of stamps.',
57
- 'getDimensions': lambda n: [n, n],
58
- 'valuesBenchmark': [5],
59
- # offset 1: hypothetically, if I were to load the offset from OEIS, I could use it to
60
- # determine if a sequence is defined at n=0, which would affect, for example, the valuesTestValidation.
61
- 'valuesTestValidation': [1, random.randint(2, 4)],
62
- },
63
- }
64
-
65
- oeisIDsImplemented: Final[List[str]] = sorted([oeisID.upper().strip() for oeisID in settingsOEIShardcodedValues.keys()])
66
- """Directly implemented OEIS IDs; standardized, e.g., 'A001415'."""
67
-
68
- def _validateOEISid(oeisIDcandidate: str):
69
- """
70
- Validates an OEIS sequence ID against implemented sequences.
71
-
72
- If the provided ID is recognized within the application's implemented
73
- OEIS sequences, the function returns the verified ID in uppercase.
74
- Otherwise, a KeyError is raised indicating that the sequence is not
75
- directly supported.
76
-
77
- Parameters:
78
- oeisIDcandidate: The OEIS sequence identifier to validate.
79
-
80
- Returns:
81
- oeisID: The validated and possibly modified OEIS sequence ID, if recognized.
82
-
83
- Raises:
84
- KeyError: If the provided sequence ID is not directly implemented.
85
- """
86
- if oeisIDcandidate in oeisIDsImplemented:
87
- return oeisIDcandidate
88
- else:
89
- oeisIDcleaned = str(oeisIDcandidate).upper().strip()
90
- if oeisIDcleaned in oeisIDsImplemented:
91
- return oeisIDcleaned
92
- else:
93
- raise KeyError(
94
- f"OEIS ID {oeisIDcandidate} is not directly implemented.\n"
95
- f"Available sequences:\n{_formatOEISsequenceInfo()}"
96
- )
97
-
98
- def _getFilenameOEISbFile(oeisID: str) -> str:
99
- oeisID = _validateOEISid(oeisID)
100
- return f"b{oeisID[1:]}.txt"
101
-
102
- def _parseBFileOEIS(OEISbFile: str, oeisID: str) -> Dict[int, int]:
103
- """
104
- Parses the content of an OEIS b-file for a given sequence ID.
105
- This function processes a multiline string representing an OEIS b-file and
106
- creates a dictionary mapping integer indices to their corresponding sequence
107
- values. The first line of the b-file is expected to contain a comment that
108
- matches the given sequence ID. If it does not match, a ValueError is raised.
109
-
110
- Parameters:
111
- OEISbFile: A multiline string representing an OEIS b-file.
112
- oeisID: The expected OEIS sequence identifier.
113
- Returns:
114
- OEISsequence: A dictionary where each key is an integer index `n` and
115
- each value is the sequence value `a(n)` corresponding to that index.
116
- Raises:
117
- ValueError: If the first line of the file does not indicate the expected
118
- sequence ID or if the content format is invalid.
119
- """
120
- bFileLines = OEISbFile.strip().splitlines()
121
- # The first line has the sequence ID
122
- if not bFileLines.pop(0).startswith(f"# {oeisID}"):
123
- raise ValueError(f"Content does not match sequence {oeisID}")
124
-
125
- OEISsequence = {}
126
- for line in bFileLines:
127
- if line.startswith('#'):
128
- continue
129
- n, aOFn = map(int, line.split())
130
- OEISsequence[n] = aOFn
131
- return OEISsequence
132
-
133
- try:
134
- _pathCache = pathlib.Path(__file__).parent / ".cache"
135
- except NameError:
136
- _pathCache = pathlib.Path.home() / ".mapFoldingCache"
137
-
138
- def _getOEISidValues(oeisID: str) -> Dict[int, int]:
139
- """
140
- Retrieves the specified OEIS sequence as a dictionary mapping integer indices
141
- to their corresponding values.
142
- This function checks for a cached local copy of the sequence data, using it if
143
- it has not expired. Otherwise, it fetches the sequence data from the OEIS
144
- website and writes it to the cache. The parsed data is returned as a dictionary
145
- mapping each index to its sequence value.
146
-
147
- Parameters:
148
- oeisID: The identifier of the OEIS sequence to retrieve.
149
- Returns:
150
- OEISsequence: A dictionary where each key is an integer index, `n`, and each
151
- value is the corresponding "a(n)" from the OEIS entry.
152
- Raises:
153
- ValueError: If the cached or downloaded file format is invalid.
154
- IOError: If there is an error reading from or writing to the local cache.
155
- """
156
-
157
- pathFilenameCache = _pathCache / _getFilenameOEISbFile(oeisID)
158
- cacheDays = 7
159
-
160
- tryCache = False
161
- if pathFilenameCache.exists():
162
- fileAge = datetime.now() - datetime.fromtimestamp(pathFilenameCache.stat().st_mtime)
163
- tryCache = fileAge < timedelta(days=cacheDays)
164
-
165
- if tryCache:
166
- try:
167
- OEISbFile = pathFilenameCache.read_text()
168
- return _parseBFileOEIS(OEISbFile, oeisID)
169
- except (ValueError, IOError):
170
- tryCache = False
171
-
172
- urlOEISbFile = f"https://oeis.org/{oeisID}/{_getFilenameOEISbFile(oeisID)}"
173
- httpResponse: urllib.response.addinfourl = urllib.request.urlopen(urlOEISbFile)
174
- OEISbFile = httpResponse.read().decode('utf-8')
175
-
176
- if not tryCache:
177
- pathFilenameCache.parent.mkdir(parents=True, exist_ok=True)
178
- pathFilenameCache.write_text(OEISbFile)
179
-
180
- return _parseBFileOEIS(OEISbFile, oeisID)
181
-
182
- def makeSettingsOEIS() -> Dict[str, SettingsOEIS]:
183
- """
184
- Creates a dictionary mapping OEIS IDs to their corresponding settings.
185
-
186
- This function initializes settings for each implemented OEIS sequence by combining
187
- hardcoded values with dynamically retrieved OEIS sequence values.
188
-
189
- Returns:
190
- Dict[str, SettingsOEIS]: A dictionary where:
191
- - Keys are OEIS sequence IDs (str)
192
- - Values are SettingsOEIS objects containing:
193
- - description: Text description of the sequence
194
- - getDimensions: Function to get dimensions
195
- - valuesBenchmark: Benchmark values
196
- - valuesKnown: Known values from OEIS
197
- - valuesTestValidation: Values for test validation
198
- - valueUnknown: First unknown value in sequence
199
-
200
- Note:
201
- Relies on global variables:
202
- - oeisIDsImplemented: List of implemented OEIS sequence IDs
203
- - settingsOEIShardcodedValues: Dictionary of hardcoded settings per sequence
204
- """
205
- settingsTarget = {}
206
- for oeisID in oeisIDsImplemented:
207
- valuesKnownSherpa = _getOEISidValues(oeisID)
208
- settingsTarget[oeisID] = SettingsOEIS(
209
- description = settingsOEIShardcodedValues[oeisID]['description'],
210
- getDimensions = settingsOEIShardcodedValues[oeisID]['getDimensions'],
211
- valuesBenchmark = settingsOEIShardcodedValues[oeisID]['valuesBenchmark'],
212
- valuesKnown = valuesKnownSherpa,
213
- valuesTestValidation = settingsOEIShardcodedValues[oeisID]['valuesTestValidation'],
214
- valueUnknown = max(valuesKnownSherpa.keys(), default=0) + 1
215
- )
216
- return settingsTarget
217
-
218
- settingsOEIS: Dict[str, SettingsOEIS] = makeSettingsOEIS()
219
- """All values and settings for `oeisIDsImplemented`."""
220
-
221
- """
222
- Section: private functions"""
223
-
224
- def _formatHelpText() -> str:
225
- """Format standardized help text for both CLI and interactive use."""
226
- exampleOEISid = oeisIDsImplemented[0]
227
- exampleN = settingsOEIS[exampleOEISid]['valuesTestValidation'][-1]
228
-
229
- return (
230
- "\nAvailable OEIS sequences:\n"
231
- f"{_formatOEISsequenceInfo()}\n"
232
- "\nUsage examples:\n"
233
- " Command line:\n"
234
- f" OEIS_for_n {exampleOEISid} {exampleN}\n"
235
- " Python:\n"
236
- " from mapFolding import oeisIDfor_n\n"
237
- f" foldsTotal = oeisIDfor_n('{exampleOEISid}', {exampleN})"
238
- )
239
-
240
- def _formatOEISsequenceInfo() -> str:
241
- """Format information about available OEIS sequences for display or error messages."""
242
- return "\n".join(
243
- f" {oeisID}: {settingsOEIS[oeisID]['description']}"
244
- for oeisID in oeisIDsImplemented
245
- )
246
-
247
- """
248
- Section: public functions"""
249
-
250
- def oeisIDfor_n(oeisID: str, n: int) -> int:
251
- """
252
- Calculate a(n) of a sequence from "The On-Line Encyclopedia of Integer Sequences" (OEIS).
253
-
254
- Parameters:
255
- oeisID: The ID of the OEIS sequence.
256
- n: A non-negative integer for which to calculate the sequence value.
257
-
258
- Returns:
259
- sequenceValue: a(n) of the OEIS sequence.
260
-
261
- Raises:
262
- ValueError: If n is negative.
263
- KeyError: If the OEIS sequence ID is not directly implemented.
264
- """
265
- oeisID = _validateOEISid(oeisID)
266
-
267
- if not isinstance(n, int) or n < 0:
268
- raise ValueError("`n` must be non-negative integer.")
269
-
270
- listDimensions = settingsOEIS[oeisID]['getDimensions'](n)
271
-
272
- if n <= 1 or len(listDimensions) < 2:
273
- foldsTotal = settingsOEIS[oeisID]['valuesKnown'].get(n, None)
274
- if foldsTotal is not None:
275
- return foldsTotal
276
- else:
277
- raise ArithmeticError(f"OEIS sequence {oeisID} is not defined at n={n}.")
278
-
279
- return countFolds(listDimensions)
280
-
281
- def OEIS_for_n() -> None:
282
- """Command-line interface for oeisIDfor_n."""
283
- import argparse
284
-
285
- parserCLI = argparse.ArgumentParser(
286
- description="Calculate a(n) for an OEIS sequence.",
287
- epilog=_formatHelpText(),
288
- formatter_class=argparse.RawDescriptionHelpFormatter
289
- )
290
- parserCLI.add_argument('oeisID', help="OEIS sequence identifier")
291
- parserCLI.add_argument('n', type=int, help="Calculate a(n) for this n")
292
-
293
- argumentsCLI = parserCLI.parse_args()
294
-
295
- timeStart = time.perf_counter()
296
-
297
- try:
298
- print(oeisIDfor_n(argumentsCLI.oeisID, argumentsCLI.n), "distinct folding patterns.")
299
- except (KeyError, ValueError, ArithmeticError) as ERRORmessage:
300
- print(f"Error: {ERRORmessage}", file=sys.stderr)
301
- sys.exit(1)
302
-
303
- timeElapsed = time.perf_counter() - timeStart
304
- print(f"Time elapsed: {timeElapsed:.3f} seconds")
305
-
306
- def clearOEIScache() -> None:
307
- """Delete all cached OEIS sequence files."""
308
- if not _pathCache.exists():
309
- print(f"Cache directory, {_pathCache}, not found - nothing to clear.")
310
- return
311
- else:
312
- for oeisID in settingsOEIS:
313
- pathFilenameCache = _pathCache / _getFilenameOEISbFile(oeisID)
314
- pathFilenameCache.unlink(missing_ok=True)
315
-
316
- print(f"Cache cleared from {_pathCache}")
317
-
318
- def getOEISids() -> None:
319
- """Print all available OEIS sequence IDs that are directly implemented."""
320
- print(_formatHelpText())
321
-
322
- if __name__ == "__main__":
323
- getOEISids()
@@ -1,47 +0,0 @@
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.someAssemblyRequired.countInitializeNoNumba 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.someAssemblyRequired.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)
@@ -1,99 +0,0 @@
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)
@@ -1,144 +0,0 @@
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
- Can create LLVM IR from the module: of unknown utility.
7
- """
8
- # from mapFolding import dtypeDefault, dtypeSmall
9
- from mapFolding import make_dtype, datatypeLarge, dtypeLarge
10
- from mapFolding.someAssemblyRequired.inlineAfunction import Z0Z_inlineMapFolding
11
- from mapFolding.someAssemblyRequired.jobsAndTasks import Z0Z_makeJob
12
- import importlib
13
- import llvmlite.binding
14
- import numpy
15
- import pathlib
16
- import pickle
17
- import python_minifier
18
-
19
- listDimensions = [6,6]
20
-
21
- # NOTE this overwrites files
22
- Z0Z_inlineMapFolding()
23
-
24
- identifierCallableLaunch = "goGoGadgetAbsurdity"
25
-
26
- def convertNDArrayToStr(arrayTarget: numpy.ndarray, identifierName: str) -> str:
27
- arrayAsTypeStr = numpy.array2string(arrayTarget, threshold=100000, max_line_width=200, separator=',')
28
- stringMinimized = python_minifier.minify(arrayAsTypeStr)
29
- commaZeroMaximum = arrayTarget.shape[-1] - 1
30
- stringMinimized = stringMinimized.replace('[0' + ',0'*commaZeroMaximum + ']', '[0]*'+str(commaZeroMaximum+1))
31
- for countZeros in range(commaZeroMaximum, 2, -1):
32
- stringMinimized = stringMinimized.replace(',0'*countZeros + ']', ']+[0]*'+str(countZeros))
33
- return f"{identifierName} = numpy.array({stringMinimized}, dtype=numpy.{arrayTarget.dtype})"
34
-
35
- def writeModuleWithNumba(listDimensions):
36
- numpy_dtypeLarge = dtypeLarge
37
- # numpy_dtypeDefault = dtypeDefault
38
- datatypeDefault = 'uint8'
39
- numpy_dtypeDefault = make_dtype(datatypeDefault)
40
- numpy_dtypeSmall = numpy_dtypeDefault
41
-
42
- parametersNumba = f"numba.types.{datatypeLarge}(), \
43
- cache=True, \
44
- "
45
- # no_cfunc_wrapper=True, \
46
- # no_cpython_wrapper=True, \
47
- # _nrt=True, \
48
- # nopython=True, \
49
- # parallel=False, \
50
- # boundscheck=False, \
51
- # error_model='numpy', \
52
- # fastmath=True, \
53
- # no_cfunc_wrapper=False, \
54
- # no_cpython_wrapper=False, \
55
- # looplift=True, \
56
- # forceinline=True, \
57
-
58
- pathFilenameData = Z0Z_makeJob(listDimensions, datatypeDefault=numpy_dtypeDefault, datatypeLarge=numpy_dtypeLarge, datatypeSmall=numpy_dtypeSmall)
59
-
60
- pathFilenameAlgorithm = pathlib.Path('/apps/mapFolding/mapFolding/someAssemblyRequired/countSequentialNoNumba.py')
61
- pathFilenameDestination = pathFilenameData.with_stem(pathFilenameData.parent.name).with_suffix(".py")
62
-
63
- lineNumba = f"@numba.jit({parametersNumba})"
64
-
65
- linesImport = "\n".join([
66
- "import numpy"
67
- , "import numba"
68
- ])
69
-
70
- stateJob = pickle.loads(pathFilenameData.read_bytes())
71
-
72
- ImaIndent = ' '
73
- linesDataDynamic = """"""
74
- linesDataDynamic = "\n".join([linesDataDynamic
75
- , ImaIndent + f"foldsTotal = numba.types.{datatypeLarge}(0)"
76
- , ImaIndent + convertNDArrayToStr(stateJob['my'], 'my')
77
- , ImaIndent + convertNDArrayToStr(stateJob['foldsSubTotals'], 'foldsSubTotals')
78
- , ImaIndent + convertNDArrayToStr(stateJob['gapsWhere'], 'gapsWhere')
79
- , ImaIndent + convertNDArrayToStr(stateJob['track'], 'track')
80
- ])
81
-
82
- linesDataStatic = """"""
83
- linesDataStatic = "\n".join([linesDataStatic
84
- , ImaIndent + convertNDArrayToStr(stateJob['the'], 'the')
85
- , ImaIndent + convertNDArrayToStr(stateJob['connectionGraph'], 'connectionGraph')
86
- ])
87
-
88
- pathFilenameFoldsTotal: pathlib.Path = stateJob['pathFilenameFoldsTotal']
89
-
90
- linesAlgorithm = """"""
91
- for lineSource in pathFilenameAlgorithm.read_text().splitlines():
92
- if lineSource.startswith('#'):
93
- continue
94
- elif not lineSource:
95
- continue
96
- elif lineSource.startswith('def '):
97
- lineSource = "\n".join([lineNumba
98
- , f"def {identifierCallableLaunch}():"
99
- , linesDataDynamic
100
- , linesDataStatic
101
- ])
102
- linesAlgorithm = "\n".join([linesAlgorithm
103
- , lineSource
104
- ])
105
-
106
- linesLaunch = """"""
107
- linesLaunch = linesLaunch + f"""
108
- if __name__ == '__main__':
109
- {identifierCallableLaunch}()"""
110
-
111
- linesWriteFoldsTotal = """"""
112
- linesWriteFoldsTotal = "\n".join([linesWriteFoldsTotal
113
- , " foldsTotal = foldsSubTotals.sum().item()"
114
- , " print(foldsTotal)"
115
- , " with numba.objmode():"
116
- , f" open('{pathFilenameFoldsTotal.as_posix()}', 'w').write(str(foldsTotal))"
117
- , " return foldsTotal"
118
- ])
119
-
120
- linesAll = "\n".join([
121
- linesImport
122
- , linesAlgorithm
123
- , linesWriteFoldsTotal
124
- , linesLaunch
125
- ])
126
-
127
- pathFilenameDestination.write_text(linesAll)
128
-
129
- return pathFilenameDestination
130
-
131
- def writeModuleLLVM(pathFilenamePythonFile: pathlib.Path) -> pathlib.Path:
132
- pathRootPackage = pathlib.Path('c:/apps/mapFolding')
133
- relativePathModule = pathFilenamePythonFile.relative_to(pathRootPackage)
134
- moduleTarget = '.'.join(relativePathModule.parts)[0:-len(relativePathModule.suffix)]
135
- moduleTargetImported = importlib.import_module(moduleTarget)
136
- linesLLVM = moduleTargetImported.__dict__[identifierCallableLaunch].inspect_llvm()[()]
137
- moduleLLVM = llvmlite.binding.module.parse_assembly(linesLLVM)
138
- pathFilenameLLVM = pathFilenamePythonFile.with_suffix(".ll")
139
- pathFilenameLLVM.write_text(str(moduleLLVM))
140
- return pathFilenameLLVM
141
-
142
- if __name__ == '__main__':
143
- pathFilenamePythonFile = writeModuleWithNumba(listDimensions)
144
- pathFilenameLLVM = writeModuleLLVM(pathFilenamePythonFile)
mapFolding/startHere.py DELETED
@@ -1,50 +0,0 @@
1
- from mapFolding import outfitCountFolds, getPathFilenameFoldsTotal, saveFoldsTotal
2
- from typing import Any, Optional, Sequence, Type, Union
3
- import os
4
-
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:
6
- """Count the total number of possible foldings for a given map dimensions.
7
-
8
- Parameters:
9
- listDimensions: List of integers representing the dimensions of the map to be folded.
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.
12
- computationDivisions (None):
13
- Whether and how to divide the computational work. See notes for details.
14
- CPUlimit (None): This is only relevant if there are `computationDivisions`: whether and how to limit the CPU usage. See notes for details.
15
- **keywordArguments: Additional arguments including `dtypeDefault` and `dtypeLarge` for data type specifications.
16
- Returns:
17
- foldsSubTotals: Total number of distinct ways to fold a map of the given dimensions.
18
-
19
- Computation divisions:
20
- - None: no division of the computation into tasks; sets task divisions to 0
21
- - int: direct set the number of task divisions; cannot exceed the map's total leaves
22
- - "maximum": divides into `leavesTotal`-many `taskDivisions`
23
- - "cpu": limits the divisions to the number of available CPUs, i.e. `concurrencyLimit`
24
-
25
- Limits on CPU usage `CPUlimit`:
26
- - `False`, `None`, or `0`: No limits on CPU usage; uses all available CPUs. All other values will potentially limit CPU usage.
27
- - `True`: Yes, limit the CPU usage; limits to 1 CPU.
28
- - Integer `>= 1`: Limits usage to the specified number of CPUs.
29
- - Decimal value (`float`) between 0 and 1: Fraction of total CPUs to use.
30
- - Decimal value (`float`) between -1 and 0: Fraction of CPUs to *not* use.
31
- - Integer `<= -1`: Subtract the absolute value from total CPUs.
32
-
33
- N.B.: You probably don't want to divide the computation into tasks.
34
- If you want to compute a large `foldsTotal`, dividing the computation into tasks is usually a bad idea. Dividing the algorithm into tasks is inherently inefficient: efficient division into tasks means there would be no overlap in the work performed by each task. When dividing this algorithm, the amount of overlap is between 50% and 90% by all tasks: at least 50% of the work done by every task must be done by _all_ tasks. If you improve the computation time, it will only change by -10 to -50% depending on (at the very least) the ratio of the map dimensions and the number of leaves. If an undivided computation would take 10 hours on your computer, for example, the computation will still take at least 5 hours but you might reduce the time to 9 hours. Most of the time, however, you will increase the computation time. If logicalCores >= leavesTotal, it will probably be faster. If logicalCores <= 2 * leavesTotal, it will almost certainly be slower for all map dimensions.
35
- """
36
- stateUniversal = outfitCountFolds(listDimensions, computationDivisions=computationDivisions, CPUlimit=CPUlimit, **keywordArguments)
37
-
38
- pathFilenameFoldsTotal = None
39
- if pathishWriteFoldsTotal is not None:
40
- pathFilenameFoldsTotal = getPathFilenameFoldsTotal(stateUniversal['mapShape'], pathishWriteFoldsTotal)
41
-
42
- from mapFolding.babbage import _countFolds
43
- _countFolds(**stateUniversal)
44
-
45
- foldsTotal = stateUniversal['foldGroups'][0:-1].sum() * stateUniversal['foldGroups'][-1]
46
-
47
- if pathFilenameFoldsTotal is not None:
48
- saveFoldsTotal(pathFilenameFoldsTotal, foldsTotal)
49
-
50
- return foldsTotal