mapFolding 0.15.4__py3-none-any.whl → 0.16.1__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 (83) hide show
  1. easyRun/A000682.py +25 -0
  2. easyRun/A005316.py +21 -0
  3. easyRun/NOTcountingFolds.py +36 -0
  4. easyRun/__init__.py +0 -0
  5. easyRun/countFolds.py +41 -0
  6. easyRun/meanders.py +71 -0
  7. mapFolding/__init__.py +10 -55
  8. mapFolding/_dataPacking.py +68 -0
  9. mapFolding/_theSSOT.py +33 -36
  10. mapFolding/_theTypes.py +21 -4
  11. mapFolding/algorithms/daoOfMapFolding.py +1 -2
  12. mapFolding/algorithms/matrixMeanders.py +101 -348
  13. mapFolding/algorithms/matrixMeandersBeDry.py +264 -0
  14. mapFolding/algorithms/matrixMeandersNumPy.py +286 -0
  15. mapFolding/algorithms/matrixMeandersPandas.py +351 -0
  16. mapFolding/algorithms/oeisIDbyFormula.py +320 -76
  17. mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +92 -0
  18. mapFolding/basecamp.py +261 -113
  19. mapFolding/beDRY.py +2 -30
  20. mapFolding/dataBaskets.py +120 -4
  21. mapFolding/oeis.py +13 -33
  22. mapFolding/reference/A000682facts.py +1276 -0
  23. mapFolding/reference/A005316facts.py +985 -0
  24. mapFolding/reference/matrixMeandersAnalysis/__init__.py +1 -0
  25. mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +15 -0
  26. mapFolding/reference/meandersDumpingGround/A005316JavaPort.py +1 -1
  27. mapFolding/reference/meandersDumpingGround/A005316imperative.py +1 -1
  28. mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +424 -0
  29. mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +54 -0
  30. mapFolding/someAssemblyRequired/A007822/__init__.py +0 -0
  31. mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +197 -0
  32. mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +74 -0
  33. mapFolding/someAssemblyRequired/RecipeJob.py +4 -4
  34. mapFolding/someAssemblyRequired/__init__.py +9 -2
  35. mapFolding/someAssemblyRequired/_toolIfThis.py +4 -3
  36. mapFolding/someAssemblyRequired/_toolkitContainers.py +8 -8
  37. mapFolding/someAssemblyRequired/infoBooth.py +27 -30
  38. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +6 -5
  39. mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +6 -4
  40. mapFolding/someAssemblyRequired/makingModules_count.py +294 -0
  41. mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +117 -0
  42. mapFolding/someAssemblyRequired/mapFolding/__init__.py +0 -0
  43. mapFolding/someAssemblyRequired/mapFolding/makeMapFoldingModules.py +220 -0
  44. mapFolding/someAssemblyRequired/meanders/__init__.py +0 -0
  45. mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +64 -0
  46. mapFolding/someAssemblyRequired/toolkitMakeModules.py +152 -0
  47. mapFolding/someAssemblyRequired/toolkitNumba.py +1 -1
  48. mapFolding/someAssemblyRequired/transformationTools.py +1 -0
  49. mapFolding/syntheticModules/A007822/__init__.py +1 -0
  50. mapFolding/syntheticModules/{algorithmA007822.py → A007822/algorithm.py} +2 -3
  51. mapFolding/syntheticModules/{algorithmA007822Numba.py → A007822/algorithmNumba.py} +3 -6
  52. mapFolding/syntheticModules/A007822/asynchronous.py +148 -0
  53. mapFolding/syntheticModules/A007822/asynchronousAnnex.py +66 -0
  54. mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +85 -0
  55. mapFolding/syntheticModules/A007822/asynchronousNumba.py +52 -0
  56. mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +53 -0
  57. mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +47 -0
  58. mapFolding/syntheticModules/{initializeStateA007822.py → A007822/initializeState.py} +1 -2
  59. mapFolding/syntheticModules/{theorem2A007822.py → A007822/theorem2.py} +1 -2
  60. mapFolding/syntheticModules/{theorem2A007822Numba.py → A007822/theorem2Numba.py} +6 -4
  61. mapFolding/syntheticModules/{theorem2A007822Trimmed.py → A007822/theorem2Trimmed.py} +1 -2
  62. mapFolding/syntheticModules/countParallelNumba.py +5 -2
  63. mapFolding/syntheticModules/daoOfMapFoldingNumba.py +4 -2
  64. mapFolding/syntheticModules/dataPacking.py +4 -2
  65. mapFolding/syntheticModules/dataPackingA007822.py +92 -26
  66. mapFolding/syntheticModules/meanders/__init__.py +1 -0
  67. mapFolding/syntheticModules/meanders/bigInt.py +62 -0
  68. mapFolding/syntheticModules/theorem2Numba.py +3 -2
  69. mapFolding/tests/conftest.py +28 -13
  70. mapFolding/tests/test_computations.py +69 -62
  71. mapFolding/tests/test_oeis.py +6 -6
  72. mapFolding/zCuzDocStoopid/__init__.py +4 -0
  73. mapFolding/zCuzDocStoopid/makeDocstrings.py +68 -0
  74. mapfolding-0.16.1.dist-info/METADATA +99 -0
  75. mapfolding-0.16.1.dist-info/RECORD +114 -0
  76. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/top_level.txt +1 -0
  77. mapFolding/someAssemblyRequired/A007822rawMaterials.py +0 -46
  78. mapFolding/someAssemblyRequired/makeAllModules.py +0 -764
  79. mapfolding-0.15.4.dist-info/METADATA +0 -78
  80. mapfolding-0.15.4.dist-info/RECORD +0 -78
  81. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/WHEEL +0 -0
  82. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/entry_points.txt +0 -0
  83. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/licenses/LICENSE +0 -0
mapFolding/dataBaskets.py CHANGED
@@ -22,10 +22,13 @@ access patterns that enable efficient result persistence and retrieval.
22
22
  """
23
23
  from mapFolding import (
24
24
  Array1DElephino, Array1DLeavesTotal, Array3DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal,
25
- getConnectionGraph, getLeavesTotal, makeDataContainer)
25
+ getConnectionGraph, getLeavesTotal, makeDataContainer, ShapeArray, ShapeSlicer)
26
+ from numpy.typing import NDArray
27
+ from typing import Final, TypeAlias
26
28
  import dataclasses
29
+ import numpy
27
30
 
28
- @dataclasses.dataclass
31
+ @dataclasses.dataclass(slots=True)
29
32
  class MapFoldingState:
30
33
  """Core computational state for map folding algorithms.
31
34
 
@@ -154,8 +157,8 @@ class MapFoldingState:
154
157
  if self.leafComparison is None: self.leafComparison = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['leafComparison'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison] # noqa: E701
155
158
 
156
159
  @dataclasses.dataclass
157
- class ParallelMapFoldingState(MapFoldingState):
158
- """Experimental computational state for task division operations.
160
+ class ParallelMapFoldingState(MapFoldingState): # This identifier because of `dataclassIdentifierParallel: identifierDotAttribute = 'Parallel' + dataclassIdentifier`.
161
+ """Computational state for task division operations.
159
162
 
160
163
  (AI generated docstring)
161
164
 
@@ -268,3 +271,116 @@ class LeafSequenceState(MapFoldingState):
268
271
  if self.leafSequence is None: # pyright: ignore[reportUnnecessaryComparison]
269
272
  self.leafSequence = makeDataContainer(groupsOfFoldsKnown, self.__dataclass_fields__['leafSequence'].metadata['dtype'])
270
273
  self.leafSequence[self.groupsOfFolds] = self.leaf1ndex
274
+
275
+ @dataclasses.dataclass(slots=True)
276
+ class MatrixMeandersState:
277
+ """Hold the state of a meanders transfer matrix algorithm computation."""
278
+
279
+ n: int
280
+ """The index of the meanders problem being solved."""
281
+ oeisID: str
282
+ """'A000682', semi-meanders, or 'A005316', meanders."""
283
+ kOfMatrix: int
284
+ """The number of iterations remaining in the transfer matrix algorithm."""
285
+ dictionaryMeanders: dict[int, int]
286
+ """A Python `dict` (*dict*ionary) of `arcCode` to `crossings`. The values are stored as Python `int`
287
+ (*int*eger), which may be arbitrarily large. Because of that property, `int` may also be called a 'bignum' (big *num*ber) or
288
+ 'bigint' (big *int*eger)."""
289
+
290
+ bitWidth: int = 0
291
+ """At the start of an iteration enumerated by `kOfMatrix`, the number of bits of the largest value `arcCode`. The
292
+ `dataclass` computes a `property` from `bitWidth`."""
293
+
294
+ @property
295
+ def MAXIMUMarcCode(self) -> int:
296
+ """Compute the maximum value of `arcCode` for the current iteration of the transfer matrix."""
297
+ return 1 << (2 * self.kOfMatrix + 4)
298
+
299
+ @property
300
+ def locatorBits(self) -> int:
301
+ """Compute an odd-parity bit-mask with `bitWidth` bits.
302
+
303
+ Notes
304
+ -----
305
+ In binary, `locatorBitsAlpha` has alternating 0s and 1s and ends with a 1, such as '101', '0101', and '10101'. The last
306
+ digit is in the 1's column, but programmers usually call it the "least significant bit" (LSB). If we count the columns
307
+ from the right, the 1's column is column 1, the 2's column is column 2, the 4's column is column 3, and so on. When
308
+ counting this way, `locatorBitsAlpha` has 1s in the columns with odd index numbers. Mathematicians and programmers,
309
+ therefore, tend to call `locatorBitsAlpha` something like the "odd bit-mask", the "odd-parity numbers", or simply "odd
310
+ mask" or "odd numbers". In addition to "odd" being inherently ambiguous in this context, this algorithm also segregates
311
+ odd numbers from even numbers, so I avoid using "odd" and "even" in the names of these bit-masks.
312
+
313
+ """
314
+ return sum(1 << one for one in range(0, self.bitWidth, 2))
315
+
316
+ @dataclasses.dataclass(slots=True)
317
+ class MatrixMeandersNumPyState(MatrixMeandersState):
318
+ """Hold the state of a meanders transfer matrix algorithm computation."""
319
+
320
+ arrayMeanders: NDArray[numpy.uint64] = dataclasses.field(default_factory=lambda: numpy.empty((0,), dtype=numpy.uint64))
321
+
322
+ bitWidthLimitArcCode: int | None = None
323
+ bitWidthLimitCrossings: int | None = None
324
+
325
+ datatypeArcCode: TypeAlias = numpy.uint64 # noqa: UP040
326
+ """The fixed-size integer type used to store `arcCode`."""
327
+ datatypeCrossings: TypeAlias = numpy.uint64 # noqa: UP040
328
+ """The fixed-size integer type used to store `crossings`."""
329
+
330
+ indexTarget: int = 0
331
+ """What is being indexed depends on the algorithm flavor."""
332
+
333
+ # TODO Integrate this better into the dataclasses paradigm.
334
+ indicesMeanders: Final[int] = 2
335
+ indexArcCode, indexCrossings = range(indicesMeanders)
336
+
337
+ @property
338
+ def slicerArcCode(self) -> ShapeSlicer:
339
+ """Get a `ShapeSlicer` to extract the `arcCode` column from `arrayMeanders`."""
340
+ return ShapeSlicer(length=..., indices=self.indexArcCode)
341
+
342
+ @property
343
+ def slicerCrossings(self) -> ShapeSlicer:
344
+ """Get a `ShapeSlicer` to extract the `crossings` column from `arrayMeanders`."""
345
+ return ShapeSlicer(length=..., indices=self.indexCrossings)
346
+
347
+ def __post_init__(self) -> None:
348
+ """Post init."""
349
+ if self.bitWidthLimitArcCode is None:
350
+ _bitWidthOfFixedSizeInteger: int = numpy.dtype(self.datatypeArcCode).itemsize * 8 # bits
351
+
352
+ _offsetNecessary: int = 3 # For example, `bitsZulu << 3`.
353
+ _offsetSafety: int = 1 # I don't have mathematical proof of how many extra bits I need.
354
+ _offset: int = _offsetNecessary + _offsetSafety
355
+
356
+ self.bitWidthLimitArcCode = _bitWidthOfFixedSizeInteger - _offset
357
+
358
+ del _bitWidthOfFixedSizeInteger, _offsetNecessary, _offsetSafety, _offset
359
+
360
+ if self.bitWidthLimitCrossings is None:
361
+ _bitWidthOfFixedSizeInteger: int = numpy.dtype(self.datatypeCrossings).itemsize * 8 # bits
362
+
363
+ _offsetNecessary: int = 0 # I don't know of any.
364
+ _offsetEstimation: int = 3 # See reference directory.
365
+ _offsetSafety: int = 1
366
+ _offset: int = _offsetNecessary + _offsetEstimation + _offsetSafety
367
+
368
+ self.bitWidthLimitCrossings = _bitWidthOfFixedSizeInteger - _offset
369
+
370
+ del _bitWidthOfFixedSizeInteger, _offsetNecessary, _offsetEstimation, _offsetSafety, _offset
371
+
372
+ def makeDictionary(self) -> None:
373
+ """Convert from NumPy `ndarray` (*Num*erical *Py*thon *n-d*imensional array) to Python `dict` (*dict*ionary)."""
374
+ self.dictionaryMeanders = {int(key): int(value) for key, value in zip(
375
+ self.arrayMeanders[self.slicerArcCode], self.arrayMeanders[self.slicerCrossings]
376
+ , strict=True)}
377
+ self.arrayMeanders = numpy.empty((0,), dtype=self.datatypeArcCode)
378
+
379
+ def makeArray(self) -> None:
380
+ """Convert from Python `dict` (*dict*ionary) to NumPy `ndarray` (*Num*erical *Py*thon *n-d*imensional array)."""
381
+ shape = ShapeArray(length=len(self.dictionaryMeanders), indices=self.indicesMeanders)
382
+ self.arrayMeanders = numpy.zeros(shape, dtype=self.datatypeArcCode)
383
+ self.arrayMeanders[self.slicerArcCode] = list(self.dictionaryMeanders.keys())
384
+ self.arrayMeanders[self.slicerCrossings] = list(self.dictionaryMeanders.values())
385
+ self.bitWidth = int(self.arrayMeanders[self.slicerArcCode].max()).bit_length()
386
+ self.dictionaryMeanders = {}
mapFolding/oeis.py CHANGED
@@ -27,7 +27,7 @@ completes the journey from configuration foundation to mathematical discovery.
27
27
  from datetime import datetime, timedelta, UTC
28
28
  from hunterMakesPy import writeStringToHere
29
29
  from itertools import chain
30
- from mapFolding import countFolds, MetadataOEISidMapFolding, MetadataOEISidMeanders, packageSettings
30
+ from mapFolding import countFolds, MetadataOEISid, MetadataOEISidMapFolding, packageSettings
31
31
  from mapFolding._theSSOT import pathCache
32
32
  from pathlib import Path
33
33
  from typing import Final
@@ -248,7 +248,7 @@ def getOEISidInformation(oeisID: str) -> tuple[str, int]:
248
248
  description: str = ' '.join(listDescriptionDeconstructed)
249
249
  return description, offset
250
250
 
251
- def _makeDictionaryOEIS() -> dict[str, MetadataOEISidMapFolding]:
251
+ def _makeDictionaryOEISMapFolding() -> dict[str, MetadataOEISidMapFolding]:
252
252
  """Construct the comprehensive settings dictionary for all implemented OEIS sequences.
253
253
 
254
254
  (AI generated docstring)
@@ -287,8 +287,8 @@ def _makeDictionaryOEIS() -> dict[str, MetadataOEISidMapFolding]:
287
287
  )
288
288
  return dictionaryOEIS
289
289
 
290
- dictionaryOEISMapFolding: dict[str, MetadataOEISidMapFolding] = _makeDictionaryOEIS()
291
- """Metadata for each OEIS sequence ID."""
290
+ dictionaryOEISMapFolding: dict[str, MetadataOEISidMapFolding] = _makeDictionaryOEISMapFolding()
291
+ """Metadata for each MapFolding OEIS ID."""
292
292
 
293
293
  def makeDictionaryFoldsTotalKnown() -> dict[tuple[int, ...], int]:
294
294
  """Make a `mapShape` to known `foldsTotal` dictionary.
@@ -418,9 +418,10 @@ def oeisIDfor_n(oeisID: str, n: int) -> int:
418
418
  message = f"OEIS sequence {oeisID} is not defined at {n = }."
419
419
  raise ArithmeticError(message)
420
420
  foldsTotal: int = dictionaryOEISMapFolding[oeisID]['valuesKnown'][n]
421
- return foldsTotal
421
+ else:
422
+ foldsTotal = countFolds(mapShape=mapShape)
422
423
 
423
- return countFolds(mapShape, oeisID=oeisID)
424
+ return foldsTotal
424
425
 
425
426
  def OEIS_for_n() -> None:
426
427
  """Command-line interface for calculating OEIS sequence values.
@@ -466,27 +467,6 @@ def OEIS_for_n() -> None:
466
467
  timeElapsed: float = time.perf_counter() - timeStart
467
468
  print(f"Time elapsed: {timeElapsed:.3f} seconds") # noqa: T201
468
469
 
469
- def clearOEIScache() -> None:
470
- """Delete all cached OEIS sequence files from the local cache directory.
471
-
472
- (AI generated docstring)
473
-
474
- This function removes all cached OEIS data files, including both sequence value files (b-files)
475
- and metadata files, forcing fresh retrieval from the OEIS website on the next access. This is
476
- useful for clearing stale cache data or troubleshooting network-related issues.
477
-
478
- The function safely handles missing files and provides user feedback about the cache clearing
479
- operation. If the cache directory does not exist, an informative message is displayed.
480
-
481
- """
482
- if not pathCache.exists():
483
- print(f"Cache directory, {pathCache}, not found - nothing to clear.") # noqa: T201
484
- return
485
- for oeisID in dictionaryOEISMapFolding:
486
- ( pathCache / f"{oeisID}.txt" ).unlink(missing_ok=True)
487
- ( pathCache / _getFilenameOEISbFile(oeisID) ).unlink(missing_ok=True)
488
- print(f"Cache cleared from {pathCache}") # noqa: T201
489
-
490
470
  def getOEISids() -> None:
491
471
  """Display comprehensive information about all implemented OEIS sequences.
492
472
 
@@ -503,21 +483,21 @@ def getOEISids() -> None:
503
483
  """
504
484
  print(_formatHelpText()) # noqa: T201
505
485
 
506
- def _makeDictionaryOEISMeanders() -> dict[str, MetadataOEISidMeanders]:
507
- dictionary: dict[str, MetadataOEISidMeanders] = {}
508
- for oeisID in packageSettings.OEISidMeandersManuallySet:
486
+ def _makeDictionaryOEIS() -> dict[str, MetadataOEISid]:
487
+ dictionary: dict[str, MetadataOEISid] = {}
488
+ for oeisID in packageSettings.OEISidManuallySet:
509
489
  valuesKnownSherpa: dict[int, int] = getOEISidValues(oeisID)
510
490
  descriptionSherpa, offsetSherpa = getOEISidInformation(oeisID)
511
- dictionary[oeisID] = MetadataOEISidMeanders(
491
+ dictionary[oeisID] = MetadataOEISid(
512
492
  description=descriptionSherpa,
513
493
  offset=offsetSherpa,
514
494
  valuesKnown=valuesKnownSherpa,
515
- valuesTestValidation=packageSettings.OEISidMeandersManuallySet[oeisID]['valuesTestValidation'],
495
+ valuesTestValidation=[*(packageSettings.OEISidManuallySet[oeisID]['valuesTestValidation']), offsetSherpa],
516
496
  valueUnknown=max(valuesKnownSherpa.keys(), default=0) + 1,
517
497
  )
518
498
  return dictionary
519
499
 
520
- dictionaryOEISMeanders: dict[str, MetadataOEISidMeanders] = _makeDictionaryOEISMeanders()
500
+ dictionaryOEIS: dict[str, MetadataOEISid] = _makeDictionaryOEIS()
521
501
 
522
502
  if __name__ == "__main__":
523
503
  getOEISids()