mapFolding 0.3.8__py3-none-any.whl → 0.3.10__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 (48) hide show
  1. mapFolding/__init__.py +56 -0
  2. mapFolding/basecamp.py +55 -0
  3. mapFolding/beDRY.py +376 -0
  4. mapFolding/oeis.py +339 -0
  5. mapFolding/someAssemblyRequired/__init__.py +2 -0
  6. {someAssemblyRequired → mapFolding/someAssemblyRequired}/makeJob.py +4 -5
  7. mapFolding/someAssemblyRequired/synthesizeJobNumba.py +383 -0
  8. mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +29 -0
  9. {someAssemblyRequired → mapFolding/someAssemblyRequired}/synthesizeModulesNumba.py +186 -99
  10. syntheticModules/numbaInitialize.py → mapFolding/syntheticModules/numba_countInitialize.py +6 -9
  11. syntheticModules/numbaParallel.py → mapFolding/syntheticModules/numba_countParallel.py +4 -4
  12. syntheticModules/numbaSequential.py → mapFolding/syntheticModules/numba_countSequential.py +5 -5
  13. mapFolding/syntheticModules/numba_doTheNeedful.py +30 -0
  14. mapFolding/theDao.py +213 -0
  15. mapFolding/theSSOT.py +251 -0
  16. mapFolding/theSSOTnumba.py +115 -0
  17. mapFolding-0.3.10.dist-info/LICENSE +407 -0
  18. {mapFolding-0.3.8.dist-info → mapFolding-0.3.10.dist-info}/METADATA +9 -11
  19. mapFolding-0.3.10.dist-info/RECORD +40 -0
  20. mapFolding-0.3.10.dist-info/top_level.txt +2 -0
  21. tests/__init__.py +1 -0
  22. tests/conftest.py +183 -0
  23. tests/conftest_tmpRegistry.py +62 -0
  24. tests/conftest_uniformTests.py +53 -0
  25. tests/test_oeis.py +141 -0
  26. tests/test_other.py +259 -0
  27. tests/test_tasks.py +44 -0
  28. tests/test_types.py +5 -0
  29. benchmarks/benchmarking.py +0 -67
  30. citations/constants.py +0 -3
  31. citations/updateCitation.py +0 -354
  32. mapFolding-0.3.8.dist-info/RECORD +0 -26
  33. mapFolding-0.3.8.dist-info/top_level.txt +0 -5
  34. someAssemblyRequired/__init__.py +0 -1
  35. someAssemblyRequired/synthesizeModuleJobNumba.py +0 -212
  36. syntheticModules/__init__.py +0 -3
  37. {reference → mapFolding/reference}/flattened.py +0 -0
  38. {reference → mapFolding/reference}/hunterNumba.py +0 -0
  39. {reference → mapFolding/reference}/irvineJavaPort.py +0 -0
  40. {reference → mapFolding/reference}/jax.py +0 -0
  41. {reference → mapFolding/reference}/lunnan.py +0 -0
  42. {reference → mapFolding/reference}/lunnanNumpy.py +0 -0
  43. {reference → mapFolding/reference}/lunnanWhile.py +0 -0
  44. {reference → mapFolding/reference}/rotatedEntryPoint.py +0 -0
  45. {reference → mapFolding/reference}/total_countPlus1vsPlusN.py +0 -0
  46. {someAssemblyRequired → mapFolding/someAssemblyRequired}/getLLVMforNoReason.py +0 -0
  47. {mapFolding-0.3.8.dist-info → mapFolding-0.3.10.dist-info}/WHEEL +0 -0
  48. {mapFolding-0.3.8.dist-info → mapFolding-0.3.10.dist-info}/entry_points.txt +0 -0
@@ -1,354 +0,0 @@
1
- from cffconvert.cli.create_citation import create_citation
2
- from mapFolding.citations.constants import GITHUB_API_VERSION_HEADER
3
- from packaging.metadata import Metadata as PyPAMetadata
4
- from typing import Any, Dict, List
5
- import attrs
6
- import cffconvert
7
- import os
8
- import packaging
9
- import packaging.metadata
10
- import packaging.utils
11
- import packaging.version
12
- import pathlib
13
- import requests
14
- import ruamel.yaml
15
- import tomli
16
-
17
- listProjectURLsTarget: List[str] = ["homepage", "license", "repository"]
18
-
19
- """
20
- Tentative plan:
21
- - Commit and push to GitHub
22
- - GitHub Action gathers information from the sources of truth
23
- - If the citation needs to be updated, write to both
24
- - pathFilenameCitationSSOT
25
- - pathFilenameCitationDOTcffRepo
26
- - Commit and push to GitHub
27
- - this complicates things
28
- - I want the updated citation to be in the `commit` field of itself: but the commit field isn't even working right now
29
- """
30
-
31
- @attrs.define
32
- class CitationNexus:
33
- """
34
- - one-to-one correlation with `cffconvert.lib.cff_1_2_x.citation` class Citation_1_2_x.cffobj
35
- """
36
- cffDASHversion: str
37
- message: str
38
-
39
- abstract: str | None = None
40
- authors: list[dict[str,str]] = attrs.field(factory=list)
41
- # GitHub TODO
42
- commit: str | None = None
43
- contact: list[dict[str,str]] = attrs.field(factory=list)
44
- dateDASHreleased: str | None = None
45
- doi: str | None = None
46
- identifiers: list[str] = attrs.field(factory=list)
47
- keywords: list[str] = attrs.field(factory=list)
48
- license: str | None = None
49
- licenseDASHurl: str | None = None
50
- preferredDASHcitation: str | None = None
51
- # TODO bibtex files in pathCitationSSOT. Conversion method and timing TBD.
52
- references: list[str] = attrs.field(factory=list)
53
- repository: str | None = None
54
- repositoryDASHartifact: str | None = None
55
- repositoryDASHcode: str | None = None
56
- title: str | None = None
57
- type: str | None = None
58
- url: str | None = None
59
- version: str | None = None
60
-
61
- def setInStone(self, prophet: str) -> "CitationNexus":
62
- match prophet:
63
- case "Citation":
64
- pass
65
- # "freeze" these items
66
- # setattr(self.cffDASHversion, 'type', Final[str])
67
- # setattr(self.doi, 'type', Final[str])
68
- # cffDASHversion: str
69
- # message: str
70
- # abstract: str | None = None
71
- # doi: str | None = None
72
- # preferredDASHcitation: str | None = None
73
- # type: str | None = None
74
- case "GitHub":
75
- pass
76
- # "freeze" these items
77
- # setattr(self.commit, 'type', Final[str])
78
- # setattr(self.dateDASHreleased, 'type', Final[str])
79
- # setattr(self.identifiers, 'type', Final[list[str]])
80
- # setattr(self.repositoryDASHcode, 'type', Final[str])
81
- case "PyPA":
82
- pass
83
- # "freeze" these items
84
- # setattr(self.keywords, 'type', Final[list[str]])
85
- # setattr(self.license, 'type', Final[str])
86
- # setattr(self.licenseDASHurl, 'type', Final[str])
87
- # setattr(self.repository, 'type', Final[str])
88
- # setattr(self.url, 'type', Final[str])
89
- # setattr(self.version, 'type', Final[str])
90
- case "PyPI":
91
- pass
92
- # "freeze" these items
93
- # setattr(self.repositoryDASHartifact, 'type', Final[str])
94
- case "pyprojectDOTtoml":
95
- pass
96
- # "freeze" these items
97
- # setattr(self.authors, 'type', Final[list[dict[str,str]]])
98
- # setattr(self.contact, 'type', Final[list[dict[str,str]]])
99
- # setattr(self.title, 'type', Final[str])
100
- return self
101
-
102
- def addPypaMetadata(nexusCitation: CitationNexus, metadata: PyPAMetadata) -> CitationNexus:
103
- if not metadata.name:
104
- raise ValueError("Metadata name is required.")
105
-
106
- nexusCitation.title = metadata.name
107
- if metadata.version: nexusCitation.version = str(metadata.version)
108
- if metadata.keywords: nexusCitation.keywords = metadata.keywords
109
- if metadata.license_expression: nexusCitation.license = metadata.license_expression
110
-
111
- Z0Z_lookup: Dict[str, str] = {
112
- "homepage": "url",
113
- "license": "licenseDASHurl",
114
- "repository": "repository",
115
- }
116
- if metadata.project_urls:
117
- for urlTarget in listProjectURLsTarget:
118
- url = metadata.project_urls.get(urlTarget, None)
119
- if url:
120
- setattr(nexusCitation, Z0Z_lookup[urlTarget], url)
121
-
122
- nexusCitation = nexusCitation.setInStone("PyPA")
123
- return nexusCitation
124
-
125
- def add_pyprojectDOTtoml(nexusCitation: CitationNexus, packageData: Dict[str, Any]) -> CitationNexus:
126
- def Z0Z_ImaNotValidatingNoNames(person: Dict[str, str]) -> Dict[str, str]:
127
- cffPerson: Dict[str, str] = {}
128
- if person.get('name', None):
129
- cffPerson['given-names'], cffPerson['family-names'] = person['name'].split(' ', 1)
130
- if person.get('email', None):
131
- cffPerson['email'] = person['email']
132
- return cffPerson
133
- listAuthors = packageData.get("authors", None)
134
- if not listAuthors:
135
- raise ValueError("Authors are required.")
136
- else:
137
- listPersons = []
138
- for person in listAuthors:
139
- listPersons.append(Z0Z_ImaNotValidatingNoNames(person))
140
- nexusCitation.authors = listPersons
141
- if packageData.get("maintainers", None):
142
- listPersons = []
143
- for person in packageData["maintainers"]:
144
- listPersons.append(Z0Z_ImaNotValidatingNoNames(person))
145
- nexusCitation.contact = listPersons
146
- nexusCitation.title = packageData["name"]
147
- nexusCitation = nexusCitation.setInStone("pyprojectDOTtoml")
148
- return nexusCitation
149
-
150
- def getGitHubRelease(nexusCitation: CitationNexus) -> Dict[str, Any]:
151
- """Return a dictionary with GitHub release data.
152
-
153
- The dictionary contains the following keys:
154
- commit: The commit hash (using the API field 'target_commitish').
155
- date-released: The published date (in YYYY-MM-DD format).
156
- identifiers: A list with one identifier object, whose description is
157
- 'The URL for {nexusCitation.title} {nexusCitation.version}.'
158
- repository-code: A URL for the commit in the repository.
159
-
160
- Raises:
161
- ValueError: If the nexusCitation.repository is not set or cannot be parsed.
162
- RuntimeError: If the HTTP request to GitHub fails.
163
- """
164
- if not nexusCitation.repository:
165
- raise ValueError("Repository URL is required to get GitHub release info.")
166
-
167
- urlparts = nexusCitation.repository.replace("https://github.com", "", 1).strip("/").split("/") + [None] * 5
168
- ownername, reponame, _2, refvalue, *_filename_parts = urlparts
169
- reponame = reponame.replace(".git", "") # type: ignore # Remove .git from the repository name, if present.
170
- assert ownername is not None, "URL should include the name of the owner/organization."
171
- assert reponame is not None, "URL should include the name of the repository."
172
- if refvalue is None:
173
- repos_api = f"https://api.github.com/repos/{ownername}/{reponame}/releases/latest"
174
- headers = GITHUB_API_VERSION_HEADER
175
- headers.update({"Accept": "application/vnd.github+json"})
176
- token = os.environ.get("GITHUB_TOKEN")
177
- headers.update({"Authorization": f"Bearer { token }"})
178
- response = requests.get(repos_api, headers=headers)
179
- if response.status_code != 200:
180
- raise RuntimeError(f"Failed to get GitHub release info: {response.status_code}")
181
-
182
- releaseData = response.json()
183
- # commitHash = releaseData.get("target_commitish")
184
- publishedAt = releaseData.get("published_at")
185
- if publishedAt:
186
- # Convert ISO timestamp (e.g., "2020-12-31T12:34:56Z") to "YYYY-MM-DD".
187
- publishedAt = publishedAt.split("T")[0]
188
-
189
- releaseHtmlUrl = releaseData.get("html_url")
190
- identifierDescription = f"The URL for {nexusCitation.title} {nexusCitation.version}."
191
- return {
192
- # "commit": commitHash,
193
- "dateDASHreleased": publishedAt,
194
- "identifiers": [{
195
- "type": "url",
196
- "value": releaseHtmlUrl,
197
- "description": identifierDescription,
198
- }],
199
- "repositoryDASHcode": releaseHtmlUrl,
200
- }
201
-
202
- def addGitHubRelease(nexusCitation: CitationNexus) -> CitationNexus:
203
- """
204
- Update the nexusCitation with GitHub release information.
205
-
206
- This function populates the following fields on the nexusCitation:
207
- - commit: using the commit hash from GitHub.
208
- - dateDASHreleased: the release date.
209
- - identifiers: appends a GitHub-specific identifier.
210
- - repositoryDASHcode: the URL to view the commit in the repository.
211
-
212
- Returns:
213
- The updated CitationNexus instance.
214
-
215
- Raises:
216
- Any exception raised by getGitHubRelease.
217
- """
218
- gitHubReleaseData = getGitHubRelease(nexusCitation)
219
- nexusCitation.commit = gitHubReleaseData.get("commit")
220
- nexusCitation.dateDASHreleased = gitHubReleaseData.get("dateDASHreleased")
221
- # Overwrite the existing list of identifiers. This could be better
222
- nexusCitation.identifiers = gitHubReleaseData.get("identifiers", [])
223
- nexusCitation.repositoryDASHcode = gitHubReleaseData.get("repositoryDASHcode")
224
- return nexusCitation
225
-
226
- def getPyPIrelease(nexusCitation: CitationNexus) -> Dict[str, Any]:
227
- if not nexusCitation.title:
228
- raise ValueError("Package name (title) is required to get PyPI release info.")
229
- if not nexusCitation.version:
230
- raise ValueError("Package version is required to get PyPI release info.")
231
-
232
- packageName = packaging.utils.canonicalize_name(nexusCitation.title)
233
- version = str(nexusCitation.version)
234
- return {
235
- "repositoryDASHartifact": f"https://pypi.org/project/{packageName}/{version}/"
236
- }
237
-
238
- def addPyPIrelease(nexusCitation: CitationNexus) -> CitationNexus:
239
- pypiReleaseData = getPyPIrelease(nexusCitation)
240
- nexusCitation.repositoryDASHartifact = pypiReleaseData.get("repositoryDASHartifact")
241
- return nexusCitation
242
-
243
- def getNexusCitation(pathFilenameCitationSSOT: pathlib.Path) -> CitationNexus:
244
-
245
- # `cffconvert.cli.create_citation.create_citation()` is PAINFULLY mundane, but a major problem
246
- # in the CFF ecosystem is divergence. Therefore, I will use this function so that my code
247
- # converges with the CFF ecosystem.
248
- citationObject: cffconvert.Citation = create_citation(infile=pathFilenameCitationSSOT, url=None)
249
- # `._parse()` is a yaml loader: use it for convergence
250
- cffobj: Dict[Any, Any] = citationObject._parse()
251
-
252
- nexusCitation = CitationNexus(
253
- cffDASHversion=cffobj["cff-version"],
254
- message=cffobj["message"],
255
- )
256
-
257
- Z0Z_list: List[attrs.Attribute] = list(attrs.fields(type(nexusCitation)))
258
- for Z0Z_field in Z0Z_list:
259
- cffobjKeyName: str = Z0Z_field.name.replace("DASH", "-")
260
- cffobjValue = cffobj.get(cffobjKeyName)
261
- if cffobjValue: # An empty list will be False
262
- setattr(nexusCitation, Z0Z_field.name, cffobjValue)
263
-
264
- nexusCitation = nexusCitation.setInStone("Citation")
265
- return nexusCitation
266
-
267
- def getPypaMetadata(packageData: Dict[str, Any]) -> PyPAMetadata:
268
- """
269
- Create a PyPA metadata object (version 2.4) from packageData.
270
- https://packaging.python.org/en/latest/specifications/core-metadata/
271
- """
272
- dictionaryProjectURLs: Dict[str, str] = {}
273
- for urlName, url in packageData.get("urls", {}).items():
274
- urlName = urlName.lower()
275
- if urlName in listProjectURLsTarget:
276
- dictionaryProjectURLs[urlName] = url
277
-
278
- metadataRaw = packaging.metadata.RawMetadata(
279
- keywords=packageData.get("keywords", []),
280
- license_expression=packageData.get("license", {}).get("text", ""),
281
- metadata_version="2.4",
282
- name=packaging.utils.canonicalize_name(packageData.get("name", None), validate=True), # packaging.metadata.InvalidMetadata: 'name' is a required field
283
- project_urls=dictionaryProjectURLs,
284
- version=packageData.get("version", None),
285
- )
286
-
287
- metadata = PyPAMetadata().from_raw(metadataRaw)
288
- return metadata
289
-
290
- def writeCitation(nexusCitation: CitationNexus, pathFilenameCitationSSOT: pathlib.Path, pathFilenameCitationDOTcffRepo: pathlib.Path):
291
- # NOTE embarrassingly hacky process to follow
292
- parameterIndent= 2
293
- parameterLineWidth = 60
294
- yamlWorkhorse = ruamel.yaml.YAML()
295
-
296
- def srsly(Z0Z_filed, Z0Z_value):
297
- if Z0Z_value: # empty lists
298
- return True
299
- else:
300
- return False
301
-
302
- dictionaryCitation = attrs.asdict(nexusCitation, filter=srsly)
303
- for keyName in list(dictionaryCitation.keys()):
304
- dictionaryCitation[keyName.replace("DASH", "-")] = dictionaryCitation.pop(keyName)
305
-
306
- pathFilenameForValidation = pathFilenameCitationSSOT.with_stem('validation')
307
-
308
- def writeStream(pathFilename):
309
- with open(pathFilename, 'w') as pathlibIsAStealthContextManagerThatRuamelCannotDetectAndRefusesToWorkWith:
310
- yamlWorkhorse.dump(dictionaryCitation, pathlibIsAStealthContextManagerThatRuamelCannotDetectAndRefusesToWorkWith)
311
-
312
- writeStream(pathFilenameForValidation)
313
-
314
- citationObject: cffconvert.Citation = create_citation(infile=pathFilenameForValidation, url=None)
315
- if citationObject.validate() is None:
316
- writeStream(pathFilenameCitationSSOT)
317
- writeStream(pathFilenameCitationDOTcffRepo)
318
-
319
- pathFilenameForValidation.unlink()
320
-
321
- def logistics():
322
- # Prefer reliable, dynamic values over hardcoded ones
323
- pathRepoRoot = pathlib.Path(__file__).parent.parent.parent
324
- pathFilenamePackageSSOT = pathRepoRoot / 'pyproject.toml'
325
-
326
- tomlPackageData: Dict[str, Any] = tomli.loads(pathFilenamePackageSSOT.read_text())['project']
327
- # https://packaging.python.org/en/latest/specifications/pyproject-toml/
328
-
329
- packageName: str = tomlPackageData.get("name", None)
330
- if not packageName:
331
- raise ValueError("Package name is required.")
332
-
333
- filenameCitationDOTcff = 'CITATION.cff'
334
- pathCitations = pathRepoRoot / packageName / 'citations'
335
- pathFilenameCitationSSOT = pathCitations / filenameCitationDOTcff
336
- pathFilenameCitationDOTcffRepo = pathRepoRoot / filenameCitationDOTcff
337
-
338
- nexusCitation = getNexusCitation(pathFilenameCitationSSOT)
339
-
340
- pypaMetadata: PyPAMetadata = getPypaMetadata(tomlPackageData)
341
-
342
- nexusCitation = addPypaMetadata(nexusCitation, pypaMetadata)
343
- nexusCitation = add_pyprojectDOTtoml(nexusCitation, tomlPackageData)
344
-
345
- nexusCitation = addGitHubRelease(nexusCitation)
346
- nexusCitation = addPyPIrelease(nexusCitation)
347
-
348
- filenameGitHubAction = 'updateCitation.yml'
349
- pathFilenameGitHubAction = pathRepoRoot / '.github' / 'workflows' / filenameGitHubAction
350
-
351
- writeCitation(nexusCitation, pathFilenameCitationSSOT, pathFilenameCitationDOTcffRepo)
352
-
353
- if __name__ == '__main__':
354
- logistics()
@@ -1,26 +0,0 @@
1
- benchmarks/benchmarking.py,sha256=HD_0NSvuabblg94ftDre6LFnXShTe8MYj3hIodW-zV0,3076
2
- citations/constants.py,sha256=1n3AC_18LOjmMLJWDo8YOGEIvDY7oZyLtI4QwqdB6z4,73
3
- citations/updateCitation.py,sha256=ihZFafY1TtVgQ1cnVNAHGCJMgoBUR8cm1qvGobwjNKA,14949
4
- reference/flattened.py,sha256=6blZ2Y9G8mu1F3gV8SKndPE398t2VVFlsgKlyeJ765A,16538
5
- reference/hunterNumba.py,sha256=HWndRgsajOf76rbb2LDNEZ6itsdYbyV-k3wgOFjeR6c,7104
6
- reference/irvineJavaPort.py,sha256=Sj-63Z-OsGuDoEBXuxyjRrNmmyl0d7Yz_XuY7I47Oyg,4250
7
- reference/jax.py,sha256=rojyK80lOATtbzxjGOHWHZngQa47CXCLJHZwIdN2MwI,14955
8
- reference/lunnan.py,sha256=XEcql_gxvCCghb6Or3qwmPbn4IZUbZTaSmw_fUjRxZE,5037
9
- reference/lunnanNumpy.py,sha256=HqDgSwTOZA-G0oophOEfc4zs25Mv4yw2aoF1v8miOLk,4653
10
- reference/lunnanWhile.py,sha256=7NY2IKO5XBgol0aWWF_Fi-7oTL9pvu_z6lB0TF1uVHk,4063
11
- reference/rotatedEntryPoint.py,sha256=z0QyDQtnMvXNj5ntWzzJUQUMFm1-xHGLVhtYzwmczUI,11530
12
- reference/total_countPlus1vsPlusN.py,sha256=usenM8Yn_G1dqlPl7NKKkcnbohBZVZBXTQRm2S3_EDA,8106
13
- someAssemblyRequired/__init__.py,sha256=3JnAKXfaYPtmxV_4AnZ6KpCosT_0GFV5Nw7K8sz4-Uo,34
14
- someAssemblyRequired/getLLVMforNoReason.py,sha256=FtJzw2pZS3A4NimWdZsegXaU-vKeCw8m67kcfb5wvGM,894
15
- someAssemblyRequired/makeJob.py,sha256=UUCNdkFnSrlhRAjkQp2_Qv4joKGXRnNJhZ4OdxI_aqU,2628
16
- someAssemblyRequired/synthesizeModuleJobNumba.py,sha256=TCYNNI19vCw0C1FLP691VPpYknkedj-zpx-xQFVIVJU,9851
17
- someAssemblyRequired/synthesizeModulesNumba.py,sha256=aOst0EC5zStLbUSDTpyMoyQe_8_3CLX7JSdHdPmlAsY,22847
18
- syntheticModules/__init__.py,sha256=XMjNt8x24M82i1eCNVcWpIIhXwfVCnjfbb-y36RAafA,131
19
- syntheticModules/numbaInitialize.py,sha256=H8Y22wwE5kYyroztAJ5HJ2W6qfw7Fu4iVrUsCPmnFjY,4088
20
- syntheticModules/numbaParallel.py,sha256=fvprhBepBxQkY5yQInYRWb7agDVMArypGC6Y510tAcU,5452
21
- syntheticModules/numbaSequential.py,sha256=Knru1I7BBvsBDTex7NfxO2U3IEcQfz-uG4Lpw2tLhOI,3629
22
- mapFolding-0.3.8.dist-info/METADATA,sha256=hgOrdxAEB5vsBdIK41JvUc65iHQladkMBbbXwg-YPnc,7729
23
- mapFolding-0.3.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
24
- mapFolding-0.3.8.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
25
- mapFolding-0.3.8.dist-info/top_level.txt,sha256=yVG9dNZywoaddcsUdEDg7o0XOBzJd_4Z-sDaXGHpiMY,69
26
- mapFolding-0.3.8.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- benchmarks
2
- citations
3
- reference
4
- someAssemblyRequired
5
- syntheticModules
@@ -1 +0,0 @@
1
- from .makeJob import makeStateJob
@@ -1,212 +0,0 @@
1
- from mapFolding import getPathFilenameFoldsTotal, indexMy, indexTrack
2
- from mapFolding import setDatatypeElephino, setDatatypeFoldsTotal, setDatatypeLeavesTotal, setDatatypeModule, hackSSOTdatatype
3
- from someAssemblyRequired import makeStateJob
4
- from typing import Optional
5
- import importlib
6
- import importlib.util
7
- import inspect
8
- import more_itertools
9
- import numpy
10
- import pathlib
11
- import python_minifier
12
-
13
- identifierCallableLaunch = "goGoGadgetAbsurdity"
14
-
15
- def makeStrRLEcompacted(arrayTarget: numpy.ndarray, identifierName: str) -> str:
16
- """Converts a NumPy array into a compressed string representation using run-length encoding (RLE).
17
-
18
- This function takes a NumPy array and converts it into an optimized string representation by:
19
- 1. Compressing consecutive sequences of numbers into range objects
20
- 2. Minimizing repeated zeros using array multiplication syntax
21
- 3. Converting the result into a valid Python array initialization statement
22
-
23
- Parameters:
24
- arrayTarget (numpy.ndarray): The input NumPy array to be converted
25
- identifierName (str): The variable name to use in the output string
26
-
27
- Returns:
28
- str: A string containing Python code that recreates the input array in compressed form.
29
- Format: "{identifierName} = numpy.array({compressed_data}, dtype=numpy.{dtype})"
30
-
31
- Example:
32
- >>> arr = numpy.array([[0,0,0,1,2,3,4,0,0]])
33
- >>> print(makeStrRLEcompacted(arr, "myArray"))
34
- "myArray = numpy.array([[0]*3,*range(1,5),[0]*2], dtype=numpy.int64)"
35
-
36
- Notes:
37
- - Sequences of 4 or fewer numbers are kept as individual values
38
- - Sequences longer than 4 numbers are converted to range objects
39
- - Consecutive zeros are compressed using multiplication syntax
40
- - The function preserves the original array's dtype
41
- """
42
-
43
- def compressRangesNDArrayNoFlatten(arraySlice):
44
- if isinstance(arraySlice, numpy.ndarray) and arraySlice.ndim > 1:
45
- return [compressRangesNDArrayNoFlatten(arraySlice[index]) for index in range(arraySlice.shape[0])]
46
- elif isinstance(arraySlice, numpy.ndarray) and arraySlice.ndim == 1:
47
- listWithRanges = []
48
- for group in more_itertools.consecutive_groups(arraySlice.tolist()):
49
- ImaSerious = list(group)
50
- if len(ImaSerious) <= 4:
51
- listWithRanges += ImaSerious
52
- else:
53
- ImaRange = [range(ImaSerious[0], ImaSerious[-1] + 1)]
54
- listWithRanges += ImaRange
55
- return listWithRanges
56
- return arraySlice
57
-
58
- arrayAsNestedLists = compressRangesNDArrayNoFlatten(arrayTarget)
59
-
60
- stringMinimized = python_minifier.minify(str(arrayAsNestedLists))
61
- commaZeroMaximum = arrayTarget.shape[-1] - 1
62
- stringMinimized = stringMinimized.replace('[0' + ',0'*commaZeroMaximum + ']', '[0]*'+str(commaZeroMaximum+1))
63
- for countZeros in range(commaZeroMaximum, 2, -1):
64
- stringMinimized = stringMinimized.replace(',0'*countZeros + ']', ']+[0]*'+str(countZeros))
65
-
66
- stringMinimized = stringMinimized.replace('range', '*range')
67
-
68
- return f"{identifierName} = numpy.array({stringMinimized}, dtype=numpy.{arrayTarget.dtype})"
69
-
70
- def writeModuleWithNumba(listDimensions) -> pathlib.Path:
71
- """
72
- Writes a Numba-optimized Python module for map folding calculations.
73
-
74
- This function takes map dimensions and generates a specialized Python module with Numba
75
- optimizations. It processes a sequential counting algorithm, adds Numba decorators and
76
- necessary data structures, and writes the resulting code to a file.
77
-
78
- Parameters:
79
- listDimensions: List of integers representing the dimensions of the map to be folded.
80
-
81
- Returns:
82
- pathlib.Path: Path to the generated Python module file.
83
-
84
- The generated module includes:
85
- - Numba JIT compilation decorators for performance optimization
86
- - Required numpy and numba imports
87
- - Dynamic and static data structures needed for folding calculations
88
- - Processed algorithm from the original sequential counter
89
- - Launch code for standalone execution
90
- - Code to write the final fold count to a file
91
- The function handles:
92
- - Translation of original code to Numba-compatible syntax
93
- - Insertion of pre-calculated values from the state job
94
- - Management of variable declarations and assignments
95
- - Setup of proper data types for Numba optimization
96
- - Organization of the output file structure
97
-
98
- Note:
99
- The generated module requires Numba and numpy to be installed.
100
- The output file will be placed in the same directory as the folds total file,
101
- with a .py extension.
102
- """
103
- stateJob = makeStateJob(listDimensions, writeJob=False)
104
- pathFilenameFoldsTotal = getPathFilenameFoldsTotal(stateJob['mapShape'])
105
-
106
- from syntheticModules import countSequential
107
- algorithmSource = countSequential
108
- codeSource = inspect.getsource(algorithmSource)
109
-
110
- lineNumba = f"@numba.jit(numba.types.{hackSSOTdatatype('datatypeFoldsTotal')}(), cache=True, nopython=True, fastmath=True, forceinline=True, inline='always', looplift=False, _nrt=True, error_model='numpy', parallel=False, boundscheck=False, no_cfunc_wrapper=False, no_cpython_wrapper=False)"
111
-
112
- linesImport = "\n".join([
113
- "import numpy"
114
- , "import numba"
115
- ])
116
-
117
- ImaIndent = ' '
118
- linesDataDynamic = """"""
119
- linesDataDynamic = "\n".join([linesDataDynamic
120
- , ImaIndent + makeStrRLEcompacted(stateJob['gapsWhere'], 'gapsWhere')
121
- ])
122
-
123
- linesDataStatic = """"""
124
- linesDataStatic = "\n".join([linesDataStatic
125
- , ImaIndent + makeStrRLEcompacted(stateJob['connectionGraph'], 'connectionGraph')
126
- ])
127
-
128
- my = stateJob['my']
129
- track = stateJob['track']
130
- linesAlgorithm = """"""
131
- for lineSource in codeSource.splitlines():
132
- if lineSource.startswith(('#', 'import', 'from', '@numba.jit')):
133
- continue
134
- elif not lineSource:
135
- continue
136
- elif lineSource.startswith('def '):
137
- lineSource = "\n".join([lineNumba
138
- , f"def {identifierCallableLaunch}():"
139
- , linesDataDynamic
140
- , linesDataStatic
141
- ])
142
- elif 'taskIndex' in lineSource:
143
- continue
144
- elif 'my[indexMy.' in lineSource:
145
- if 'dimensionsTotal' in lineSource:
146
- continue
147
- # Statements are in the form: leaf1ndex = my[indexMy.leaf1ndex.value]
148
- identifier, statement = lineSource.split('=')
149
- lineSource = ImaIndent + identifier.strip() + f"=numba.types.{hackSSOTdatatype(identifier.strip())}({str(eval(statement.strip()))})"
150
- elif ': int =' in lineSource or ':int=' in lineSource:
151
- if 'dimensionsTotal' in lineSource:
152
- continue
153
- # Statements are in the form: groupsOfFolds: int = 0
154
- assignment, statement = lineSource.split('=')
155
- identifier = assignment.split(':')[0].strip()
156
- lineSource = ImaIndent + identifier.strip() + f"=numba.types.{hackSSOTdatatype(identifier.strip())}({str(eval(statement.strip()))})"
157
- elif 'track[indexTrack.' in lineSource:
158
- # Statements are in the form: leafAbove = track[indexTrack.leafAbove.value]
159
- identifier, statement = lineSource.split('=')
160
- lineSource = ImaIndent + makeStrRLEcompacted(eval(statement.strip()), identifier.strip())
161
- elif 'foldGroups[-1]' in lineSource:
162
- lineSource = lineSource.replace('foldGroups[-1]', str(stateJob['foldGroups'][-1]))
163
- elif 'dimensionsTotal' in lineSource:
164
- lineSource = lineSource.replace('dimensionsTotal', str(stateJob['my'][indexMy.dimensionsTotal]))
165
-
166
- linesAlgorithm = "\n".join([linesAlgorithm
167
- , lineSource
168
- ])
169
-
170
- linesLaunch = """"""
171
- linesLaunch = linesLaunch + f"""
172
- if __name__ == '__main__':
173
- # import time
174
- # timeStart = time.perf_counter()
175
- {identifierCallableLaunch}()
176
- # print(time.perf_counter() - timeStart)
177
- """
178
-
179
- linesWriteFoldsTotal = """"""
180
- linesWriteFoldsTotal = "\n".join([linesWriteFoldsTotal
181
- , f" groupsOfFolds *= {str(stateJob['foldGroups'][-1])}"
182
- , " print(groupsOfFolds)"
183
- , " with numba.objmode():"
184
- , f" open('{pathFilenameFoldsTotal.as_posix()}', 'w').write(str(groupsOfFolds))"
185
- , " return groupsOfFolds"
186
- ])
187
-
188
- linesAll = "\n".join([
189
- linesImport
190
- , linesAlgorithm
191
- , linesWriteFoldsTotal
192
- , linesLaunch
193
- ])
194
-
195
- pathFilenameDestination = pathFilenameFoldsTotal.with_suffix(".py")
196
- pathFilenameDestination.write_text(linesAll)
197
-
198
- return pathFilenameDestination
199
-
200
- if __name__ == '__main__':
201
- listDimensions = [5,5]
202
- setDatatypeFoldsTotal('int64', sourGrapes=True)
203
- setDatatypeElephino('uint8', sourGrapes=True)
204
- setDatatypeLeavesTotal('int8', sourGrapes=True)
205
- pathFilenameModule = writeModuleWithNumba(listDimensions)
206
-
207
- # Induce numba.jit compilation
208
- moduleSpec = importlib.util.spec_from_file_location(pathFilenameModule.stem, pathFilenameModule)
209
- if moduleSpec is None: raise ImportError(f"Could not load module specification from {pathFilenameModule}")
210
- module = importlib.util.module_from_spec(moduleSpec)
211
- if moduleSpec.loader is None: raise ImportError(f"Could not load module from {moduleSpec}")
212
- moduleSpec.loader.exec_module(module)
@@ -1,3 +0,0 @@
1
- from .numbaInitialize import countInitialize
2
- from .numbaParallel import countParallel
3
- from .numbaSequential import countSequential
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes