mapFolding 0.9.0__tar.gz → 0.9.2__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.9.0 → mapfolding-0.9.2}/PKG-INFO +2 -1
- mapfolding-0.9.2/mapFolding/__init__.py +94 -0
- mapfolding-0.9.2/mapFolding/basecamp.py +95 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/beDRY.py +75 -69
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/oeis.py +74 -85
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/__init__.py +2 -2
- mapfolding-0.9.2/mapFolding/someAssemblyRequired/RecipeJob.py +103 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/__init__.py +31 -29
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/_theTypes.py +9 -1
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/_tool_Make.py +1 -2
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/_tool_Then.py +16 -8
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/_toolboxAntecedents.py +111 -23
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/_toolboxContainers.py +27 -28
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/_toolboxPython.py +3 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +83 -51
- mapfolding-0.9.2/mapFolding/someAssemblyRequired/toolboxNumba.py +198 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/transformationTools.py +183 -12
- mapfolding-0.9.0/mapFolding/syntheticModules/numbaCount_doTheNeedful.py → mapfolding-0.9.2/mapFolding/syntheticModules/numbaCount.py +13 -12
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/theDao.py +37 -36
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/theSSOT.py +29 -33
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/toolboxFilesystem.py +29 -38
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding.egg-info/PKG-INFO +2 -1
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding.egg-info/SOURCES.txt +4 -3
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding.egg-info/requires.txt +1 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/pyproject.toml +3 -2
- {mapfolding-0.9.0 → mapfolding-0.9.2}/tests/test_computations.py +2 -1
- {mapfolding-0.9.0 → mapfolding-0.9.2}/tests/test_other.py +0 -7
- mapfolding-0.9.0/mapFolding/__init__.py +0 -93
- mapfolding-0.9.0/mapFolding/basecamp.py +0 -90
- mapfolding-0.9.0/mapFolding/someAssemblyRequired/toolboxNumba.py +0 -399
- {mapfolding-0.9.0 → mapfolding-0.9.2}/LICENSE +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/README.md +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/py.typed +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/flattened.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/hunterNumba.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/irvineJavaPort.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/jaxCount.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/jobsCompleted/__init__.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/jobsCompleted/p2x19/p2x19.py +0 -0
- /mapfolding-0.9.0/mapFolding/reference/lunnanNumpy.py → /mapfolding-0.9.2/mapFolding/reference/lunnonNumpy.py +0 -0
- /mapfolding-0.9.0/mapFolding/reference/lunnanWhile.py → /mapfolding-0.9.2/mapFolding/reference/lunnonWhile.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/rotatedEntryPoint.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding/syntheticModules/__init__.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding.egg-info/dependency_links.txt +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding.egg-info/entry_points.txt +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/mapFolding.egg-info/top_level.txt +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/setup.cfg +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/tests/__init__.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/tests/conftest.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/tests/test_filesystem.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/tests/test_oeis.py +0 -0
- {mapfolding-0.9.0 → mapfolding-0.9.2}/tests/test_tasks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mapFolding
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.2
|
|
4
4
|
Summary: Map folding algorithm with code transformation framework for optimizing numerical computations
|
|
5
5
|
Author-email: Hunter Hogan <HunterHogan@pm.me>
|
|
6
6
|
License: CC-BY-NC-4.0
|
|
@@ -38,6 +38,7 @@ Requires-Dist: numba
|
|
|
38
38
|
Requires-Dist: numpy
|
|
39
39
|
Requires-Dist: platformdirs
|
|
40
40
|
Requires-Dist: python_minifier
|
|
41
|
+
Requires-Dist: sympy
|
|
41
42
|
Requires-Dist: tomli
|
|
42
43
|
Requires-Dist: Z0Z_tools
|
|
43
44
|
Provides-Extra: testing
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Map folding enumeration and counting algorithms with advanced optimization capabilities.
|
|
3
|
+
|
|
4
|
+
This package implements algorithms to count and enumerate the distinct ways
|
|
5
|
+
a rectangular map can be folded, based on the mathematical problem described
|
|
6
|
+
in Lunnon's 1971 paper. It provides multiple layers of functionality, from
|
|
7
|
+
high-level user interfaces to sophisticated algorithmic optimizations and code
|
|
8
|
+
transformation tools.
|
|
9
|
+
|
|
10
|
+
Core modules:
|
|
11
|
+
- basecamp: Public API with simplified interfaces for end users
|
|
12
|
+
- theDao: Core computational algorithm using a functional state-transformation approach
|
|
13
|
+
- beDRY: Core utility functions implementing consistent data handling, validation, and
|
|
14
|
+
resource management across the package's computational assembly-line
|
|
15
|
+
- theSSOT: Single Source of Truth for configuration, types, and state management
|
|
16
|
+
- toolboxFilesystem: Cross-platform file management services for storing and retrieving
|
|
17
|
+
computation results with robust error handling and fallback mechanisms
|
|
18
|
+
- oeis: Interface to the Online Encyclopedia of Integer Sequences for known results
|
|
19
|
+
|
|
20
|
+
Extended functionality:
|
|
21
|
+
- someAssemblyRequired: Code transformation framework that optimizes the core algorithm
|
|
22
|
+
through AST manipulation, dataclass transformation, and compilation techniques
|
|
23
|
+
- The system converts readable code into high-performance implementations through
|
|
24
|
+
a systematic analysis and transformation pipeline
|
|
25
|
+
- Provides tools to "shatter" complex dataclasses into primitive components,
|
|
26
|
+
enabling compatibility with Numba and other optimization frameworks
|
|
27
|
+
- Creates specialized implementations tailored for specific input parameters
|
|
28
|
+
|
|
29
|
+
Testing and extension:
|
|
30
|
+
- tests: Comprehensive test suite designed for both verification and extension
|
|
31
|
+
- Provides fixtures and utilities that simplify testing of custom implementations
|
|
32
|
+
- Enables users to validate their own recipes and job configurations with minimal code
|
|
33
|
+
- Offers standardized testing patterns that maintain consistency across the codebase
|
|
34
|
+
- See tests/__init__.py for detailed documentation on extending the test suite
|
|
35
|
+
|
|
36
|
+
Special directories:
|
|
37
|
+
- .cache/: Stores cached data from external sources like OEIS to improve performance
|
|
38
|
+
- syntheticModules/: Contains dynamically generated, optimized implementations of the
|
|
39
|
+
core algorithm created by the code transformation framework
|
|
40
|
+
- reference/: Historical implementations and educational resources for algorithm exploration
|
|
41
|
+
- reference/jobsCompleted/: Contains successful computations for previously unknown values,
|
|
42
|
+
including first-ever calculations for 2x19 and 2x20 maps (OEIS A001415)
|
|
43
|
+
|
|
44
|
+
This package balances algorithm readability and understandability with
|
|
45
|
+
high-performance computation capabilities, allowing users to compute map folding
|
|
46
|
+
totals for larger dimensions than previously feasible while also providing
|
|
47
|
+
a foundation for exploring advanced code transformation techniques.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
from mapFolding.theSSOT import (
|
|
51
|
+
Array1DElephino as Array1DElephino,
|
|
52
|
+
Array1DFoldsTotal as Array1DFoldsTotal,
|
|
53
|
+
Array1DLeavesTotal as Array1DLeavesTotal,
|
|
54
|
+
Array3D as Array3D,
|
|
55
|
+
ComputationState as ComputationState,
|
|
56
|
+
DatatypeElephino as DatatypeElephino,
|
|
57
|
+
DatatypeFoldsTotal as DatatypeFoldsTotal,
|
|
58
|
+
DatatypeLeavesTotal as DatatypeLeavesTotal,
|
|
59
|
+
NumPyElephino as NumPyElephino,
|
|
60
|
+
NumPyFoldsTotal as NumPyFoldsTotal,
|
|
61
|
+
NumPyIntegerType as NumPyIntegerType,
|
|
62
|
+
NumPyLeavesTotal as NumPyLeavesTotal,
|
|
63
|
+
raiseIfNoneGitHubIssueNumber3 as raiseIfNoneGitHubIssueNumber3,
|
|
64
|
+
The as The,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
from mapFolding.theDao import (
|
|
68
|
+
countInitialize as countInitialize,
|
|
69
|
+
doTheNeedful as doTheNeedful,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
from mapFolding.beDRY import (
|
|
73
|
+
outfitCountFolds as outfitCountFolds,
|
|
74
|
+
setProcessorLimit as setProcessorLimit,
|
|
75
|
+
validateListDimensions as validateListDimensions,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
from mapFolding.toolboxFilesystem import (
|
|
79
|
+
getPathFilenameFoldsTotal as getPathFilenameFoldsTotal,
|
|
80
|
+
getPathRootJobDEFAULT as getPathRootJobDEFAULT,
|
|
81
|
+
saveFoldsTotal as saveFoldsTotal,
|
|
82
|
+
saveFoldsTotalFAILearly as saveFoldsTotalFAILearly,
|
|
83
|
+
writeStringToHere as writeStringToHere,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
from mapFolding.basecamp import countFolds as countFolds
|
|
87
|
+
|
|
88
|
+
from mapFolding.oeis import (
|
|
89
|
+
clearOEIScache as clearOEIScache,
|
|
90
|
+
getFoldsTotalKnown as getFoldsTotalKnown,
|
|
91
|
+
getOEISids as getOEISids,
|
|
92
|
+
OEIS_for_n as OEIS_for_n,
|
|
93
|
+
oeisIDfor_n as oeisIDfor_n,
|
|
94
|
+
)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Public API for the map folding algorithm with simplified interface.
|
|
3
|
+
|
|
4
|
+
This module provides the main entry point for users of the mapFolding package, abstracting away the complexities of the
|
|
5
|
+
computational algorithm. It offers a high-level interface to count the total number of possible ways to fold a
|
|
6
|
+
rectangular map of specified dimensions, with options for customizing the computation process and saving results.
|
|
7
|
+
|
|
8
|
+
The primary function is countFolds, which handles parameter validation, computation state management, dispatching to the
|
|
9
|
+
appropriate algorithm implementation, and optional persistence of results.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
from mapFolding import (
|
|
14
|
+
ComputationState,
|
|
15
|
+
getPathFilenameFoldsTotal,
|
|
16
|
+
outfitCountFolds,
|
|
17
|
+
saveFoldsTotal,
|
|
18
|
+
saveFoldsTotalFAILearly,
|
|
19
|
+
setProcessorLimit,
|
|
20
|
+
The,
|
|
21
|
+
validateListDimensions,
|
|
22
|
+
)
|
|
23
|
+
from os import PathLike
|
|
24
|
+
from pathlib import PurePath
|
|
25
|
+
|
|
26
|
+
def countFolds(listDimensions: Sequence[int]
|
|
27
|
+
, pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None
|
|
28
|
+
, computationDivisions: int | str | None = None
|
|
29
|
+
, CPUlimit: int | float | bool | None = None
|
|
30
|
+
) -> int:
|
|
31
|
+
"""
|
|
32
|
+
Count the total number of possible foldings for a given map dimensions.
|
|
33
|
+
|
|
34
|
+
This function serves as the main public interface to the map folding algorithm, handling all parameter validation,
|
|
35
|
+
computation state management, and result persistence in a user-friendly way.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
listDimensions
|
|
40
|
+
List of integers representing the dimensions of the map to be folded.
|
|
41
|
+
pathLikeWriteFoldsTotal: None
|
|
42
|
+
Path, filename, or pathFilename to write the total fold count to. If a directory is provided, creates a file
|
|
43
|
+
with a default name based on map dimensions.
|
|
44
|
+
computationDivisions: None
|
|
45
|
+
Whether and how to divide the computational work.
|
|
46
|
+
- `None`: no division of the computation into tasks; sets task divisions to 0.
|
|
47
|
+
- int: directly set the number of task divisions; cannot exceed the map's total leaves.
|
|
48
|
+
- `'maximum'`: divides into `leavesTotal`-many `taskDivisions`.
|
|
49
|
+
- `'cpu'`: limits the divisions to the number of available CPUs: i.e., `concurrencyLimit`.
|
|
50
|
+
CPUlimit: None
|
|
51
|
+
This is only relevant if there are `computationDivisions`: whether and how to limit the CPU usage.
|
|
52
|
+
- `False`, `None`, or `0`: No limits on processor usage; uses all available processors. All other values will
|
|
53
|
+
potentially limit processor usage.
|
|
54
|
+
- `True`: Yes, limit the processor usage; limits to 1 processor.
|
|
55
|
+
- Integer `>= 1`: Limits usage to the specified number of processors.
|
|
56
|
+
- Decimal value (`float`) between 0 and 1: Fraction of total processors to use.
|
|
57
|
+
- Decimal value (`float`) between -1 and 0: Fraction of processors to _not_ use.
|
|
58
|
+
- Integer `<= -1`: Subtract the absolute value from total processors.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
foldsTotal: Total number of distinct ways to fold a map of the given dimensions.
|
|
63
|
+
|
|
64
|
+
Note well
|
|
65
|
+
---------
|
|
66
|
+
You probably don't want to divide the computation into tasks.
|
|
67
|
+
|
|
68
|
+
If you want to compute a large `foldsTotal`, dividing the computation into tasks is usually a bad idea. Dividing the
|
|
69
|
+
algorithm into tasks is inherently inefficient: efficient division into tasks means there would be no overlap in the
|
|
70
|
+
work performed by each task. When dividing this algorithm, the amount of overlap is between 50% and 90% by all
|
|
71
|
+
tasks: at least 50% of the work done by every task must be done by _all_ tasks. If you improve the computation time,
|
|
72
|
+
it will only change by -10 to -50% depending on (at the very least) the ratio of the map dimensions and the number
|
|
73
|
+
of leaves. If an undivided computation would take 10 hours on your computer, for example, the computation will still
|
|
74
|
+
take at least 5 hours but you might reduce the time to 9 hours. Most of the time, however, you will increase the
|
|
75
|
+
computation time. If logicalCores >= `leavesTotal`, it will probably be faster. If logicalCores <= 2 * `leavesTotal`, it
|
|
76
|
+
will almost certainly be slower for all map dimensions.
|
|
77
|
+
"""
|
|
78
|
+
mapShape: tuple[int, ...] = validateListDimensions(listDimensions)
|
|
79
|
+
concurrencyLimit: int = setProcessorLimit(CPUlimit, The.concurrencyPackage)
|
|
80
|
+
computationStateInitialized: ComputationState = outfitCountFolds(mapShape, computationDivisions, concurrencyLimit)
|
|
81
|
+
|
|
82
|
+
if pathLikeWriteFoldsTotal is not None:
|
|
83
|
+
pathFilenameFoldsTotal = getPathFilenameFoldsTotal(computationStateInitialized.mapShape, pathLikeWriteFoldsTotal)
|
|
84
|
+
saveFoldsTotalFAILearly(pathFilenameFoldsTotal)
|
|
85
|
+
else:
|
|
86
|
+
pathFilenameFoldsTotal = None
|
|
87
|
+
|
|
88
|
+
computationStateComplete: ComputationState = The.dispatcher(computationStateInitialized)
|
|
89
|
+
|
|
90
|
+
computationStateComplete.getFoldsTotal()
|
|
91
|
+
|
|
92
|
+
if pathFilenameFoldsTotal is not None:
|
|
93
|
+
saveFoldsTotal(pathFilenameFoldsTotal, computationStateComplete.foldsTotal)
|
|
94
|
+
|
|
95
|
+
return computationStateComplete.foldsTotal
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Core utility functions implementing DRY (Don't Repeat Yourself) principles for the mapFolding package.
|
|
3
3
|
|
|
4
|
-
This module serves as the foundation for consistent data management and parameter validation
|
|
5
|
-
|
|
4
|
+
This module serves as the foundation for consistent data management and parameter validation across the entire
|
|
5
|
+
mapFolding computation assembly-line. It provides critical utility functions that:
|
|
6
6
|
|
|
7
7
|
1. Calculate and validate fundamental computational parameters such as leaves total and task divisions.
|
|
8
8
|
2. Generate specialized connection graphs that define the folding algorithm's constraints.
|
|
@@ -10,13 +10,12 @@ across the entire mapFolding computation assembly-line. It provides critical uti
|
|
|
10
10
|
4. Construct and manage uniform data structures for the computation state.
|
|
11
11
|
5. Ensure parameter validation and safe type conversion.
|
|
12
12
|
|
|
13
|
-
The functions in this module maintain a clear separation between data initialization and algorithm
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
The functions in this module maintain a clear separation between data initialization and algorithm implementation,
|
|
14
|
+
enabling the package to support multiple computational strategies (sequential, parallel, and JIT-compiled) while
|
|
15
|
+
ensuring consistent input handling and state management.
|
|
16
16
|
|
|
17
|
-
These utilities form a stable internal API that other modules depend on, particularly theSSOT
|
|
18
|
-
|
|
19
|
-
produce optimized implementations.
|
|
17
|
+
These utilities form a stable internal API that other modules depend on, particularly theSSOT (Single Source of Truth),
|
|
18
|
+
theDao (core algorithm), and the synthetic module generators that produce optimized implementations.
|
|
20
19
|
"""
|
|
21
20
|
from collections.abc import Sequence
|
|
22
21
|
from mapFolding import ComputationState, NumPyIntegerType
|
|
@@ -30,9 +29,8 @@ def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
|
|
|
30
29
|
"""
|
|
31
30
|
Calculate the total number of leaves in a map with the given dimensions.
|
|
32
31
|
|
|
33
|
-
The total number of leaves is the product of all dimensions in the map shape.
|
|
34
|
-
|
|
35
|
-
task divisions.
|
|
32
|
+
The total number of leaves is the product of all dimensions in the map shape. This value is foundational for
|
|
33
|
+
initializing the computation state and determining task divisions.
|
|
36
34
|
|
|
37
35
|
Parameters
|
|
38
36
|
----------
|
|
@@ -47,8 +45,8 @@ def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
|
|
|
47
45
|
Raises
|
|
48
46
|
------
|
|
49
47
|
OverflowError
|
|
50
|
-
If the product of dimensions would exceed the system's maximum integer size.
|
|
51
|
-
|
|
48
|
+
If the product of dimensions would exceed the system's maximum integer size. This check prevents silent numeric
|
|
49
|
+
overflow issues that could lead to incorrect results.
|
|
52
50
|
"""
|
|
53
51
|
productDimensions = 1
|
|
54
52
|
for dimension in mapShape:
|
|
@@ -113,10 +111,9 @@ def _makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int) -> ndarray
|
|
|
113
111
|
"""
|
|
114
112
|
Implementation of connection graph generation for map folding.
|
|
115
113
|
|
|
116
|
-
This is the internal implementation that calculates all possible connections between
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
dimension of the map.
|
|
114
|
+
This is the internal implementation that calculates all possible connections between leaves in a map folding problem
|
|
115
|
+
based on Lunnon's algorithm. The function constructs a three-dimensional array representing which leaves can be
|
|
116
|
+
connected to each other for each dimension of the map.
|
|
120
117
|
|
|
121
118
|
Parameters
|
|
122
119
|
----------
|
|
@@ -128,17 +125,16 @@ def _makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int) -> ndarray
|
|
|
128
125
|
Returns
|
|
129
126
|
-------
|
|
130
127
|
connectionGraph
|
|
131
|
-
A 3D NumPy array with shape (`dimensionsTotal`, `leavesTotal`+1, `leavesTotal`+1)
|
|
132
|
-
|
|
133
|
-
when inserting leaf i in dimension d.
|
|
128
|
+
A 3D NumPy array with shape (`dimensionsTotal`, `leavesTotal`+1, `leavesTotal`+1) where each entry [d,i,j]
|
|
129
|
+
represents the leaf that would be connected to leaf j when inserting leaf i in dimension d.
|
|
134
130
|
|
|
135
131
|
Notes
|
|
136
132
|
-----
|
|
137
|
-
This is an implementation detail and shouldn't be called directly by external code.
|
|
138
|
-
|
|
133
|
+
This is an implementation detail and shouldn't be called directly by external code. Use `getConnectionGraph`
|
|
134
|
+
instead, which applies proper typing.
|
|
139
135
|
|
|
140
|
-
The algorithm calculates a coordinate system first, then determines connections
|
|
141
|
-
|
|
136
|
+
The algorithm calculates a coordinate system first, then determines connections based on parity rules, boundary
|
|
137
|
+
conditions, and dimensional constraints.
|
|
142
138
|
"""
|
|
143
139
|
dimensionsTotal = len(mapShape)
|
|
144
140
|
cumulativeProduct = numpy.multiply.accumulate([1] + list(mapShape), dtype=numpy_int64)
|
|
@@ -169,9 +165,9 @@ def getConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: ty
|
|
|
169
165
|
"""
|
|
170
166
|
Create a properly typed connection graph for the map folding algorithm.
|
|
171
167
|
|
|
172
|
-
This function serves as a typed wrapper around the internal implementation that
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
This function serves as a typed wrapper around the internal implementation that generates connection graphs. It
|
|
169
|
+
provides the correct type information for the returned array, ensuring consistency throughout the computation
|
|
170
|
+
assembly-line.
|
|
175
171
|
|
|
176
172
|
Parameters
|
|
177
173
|
----------
|
|
@@ -180,14 +176,14 @@ def getConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: ty
|
|
|
180
176
|
leavesTotal
|
|
181
177
|
The total number of leaves in the map.
|
|
182
178
|
datatype
|
|
183
|
-
The NumPy integer type to use for the array elements, ensuring proper
|
|
184
|
-
|
|
179
|
+
The NumPy integer type to use for the array elements, ensuring proper memory usage and compatibility with the
|
|
180
|
+
computation state.
|
|
185
181
|
|
|
186
182
|
Returns
|
|
187
183
|
-------
|
|
188
184
|
connectionGraph
|
|
189
|
-
A 3D NumPy array with shape (`dimensionsTotal`, `leavesTotal`+1, `leavesTotal`+1)
|
|
190
|
-
|
|
185
|
+
A 3D NumPy array with shape (`dimensionsTotal`, `leavesTotal`+1, `leavesTotal`+1) with the specified `datatype`,
|
|
186
|
+
representing all possible connections between leaves.
|
|
191
187
|
"""
|
|
192
188
|
connectionGraph = _makeConnectionGraph(mapShape, leavesTotal)
|
|
193
189
|
connectionGraph = connectionGraph.astype(datatype)
|
|
@@ -197,18 +193,16 @@ def makeDataContainer(shape: int | tuple[int, ...], datatype: type[NumPyIntegerT
|
|
|
197
193
|
"""
|
|
198
194
|
Create a typed NumPy array container with initialized values.
|
|
199
195
|
|
|
200
|
-
This function centralizes the creation of data containers used throughout the
|
|
201
|
-
|
|
202
|
-
or implementation strategies if needed in the future.
|
|
196
|
+
This function centralizes the creation of data containers used throughout the computation assembly-line, enabling
|
|
197
|
+
easy switching between different container types or implementation strategies if needed in the future.
|
|
203
198
|
|
|
204
199
|
Parameters
|
|
205
200
|
----------
|
|
206
201
|
shape
|
|
207
|
-
Either an integer (for 1D arrays) or a tuple of integers (for multi-dimensional arrays)
|
|
208
|
-
|
|
202
|
+
Either an integer (for 1D arrays) or a tuple of integers (for multi-dimensional arrays) specifying the
|
|
203
|
+
dimensions of the array.
|
|
209
204
|
datatype
|
|
210
|
-
The NumPy integer type to use for the array elements, ensuring proper type
|
|
211
|
-
consistency and memory efficiency.
|
|
205
|
+
The NumPy integer type to use for the array elements, ensuring proper type consistency and memory efficiency.
|
|
212
206
|
|
|
213
207
|
Returns
|
|
214
208
|
-------
|
|
@@ -221,18 +215,17 @@ def outfitCountFolds(mapShape: tuple[int, ...], computationDivisions: int | str
|
|
|
221
215
|
"""
|
|
222
216
|
Initialize a `ComputationState` with validated parameters for map folding calculation.
|
|
223
217
|
|
|
224
|
-
This function serves as the central initialization point for creating a properly
|
|
225
|
-
|
|
226
|
-
|
|
218
|
+
This function serves as the central initialization point for creating a properly configured `ComputationState`
|
|
219
|
+
object, ensuring consistent calculation of the fundamental parameters (`leavesTotal` and `taskDivisions`) across the
|
|
220
|
+
entire package.
|
|
227
221
|
|
|
228
222
|
Parameters
|
|
229
223
|
----------
|
|
230
224
|
mapShape
|
|
231
225
|
A tuple of integers representing the dimensions of the map.
|
|
232
226
|
computationDivisions: None
|
|
233
|
-
Controls how to divide the computation into parallel tasks. I know it is annoying,
|
|
234
|
-
|
|
235
|
-
accurate information.
|
|
227
|
+
Controls how to divide the computation into parallel tasks. I know it is annoying, but please see
|
|
228
|
+
`getTaskDivisions` for details, so that you and I both know you have the most accurate information.
|
|
236
229
|
concurrencyLimit: 1
|
|
237
230
|
Maximum number of concurrent processes to use during computation.
|
|
238
231
|
|
|
@@ -243,9 +236,8 @@ def outfitCountFolds(mapShape: tuple[int, ...], computationDivisions: int | str
|
|
|
243
236
|
|
|
244
237
|
Notes
|
|
245
238
|
-----
|
|
246
|
-
This function maintains the Single Source of Truth principle for `leavesTotal`
|
|
247
|
-
|
|
248
|
-
throughout the package.
|
|
239
|
+
This function maintains the Single Source of Truth principle for `leavesTotal` and `taskDivisions` calculation,
|
|
240
|
+
ensuring these values are derived consistently throughout the package.
|
|
249
241
|
"""
|
|
250
242
|
leavesTotal = getLeavesTotal(mapShape)
|
|
251
243
|
taskDivisions = getTaskDivisions(computationDivisions, concurrencyLimit, leavesTotal)
|
|
@@ -260,7 +252,8 @@ def setProcessorLimit(CPUlimit: Any | None, concurrencyPackage: str | None = Non
|
|
|
260
252
|
----------
|
|
261
253
|
CPUlimit: None
|
|
262
254
|
Controls processor usage limits:
|
|
263
|
-
- `False`, `None`, or `0`: No limits on processor usage; uses all available processors. All other values will
|
|
255
|
+
- `False`, `None`, or `0`: No limits on processor usage; uses all available processors. All other values will
|
|
256
|
+
potentially limit processor usage.
|
|
264
257
|
- `True`: Yes, limit the processor usage; limits to 1 processor.
|
|
265
258
|
- Integer `>= 1`: Limits usage to the specified number of processors.
|
|
266
259
|
- Decimal value (`float`) between 0 and 1: Fraction of total processors to use.
|
|
@@ -285,12 +278,12 @@ def setProcessorLimit(CPUlimit: Any | None, concurrencyPackage: str | None = Non
|
|
|
285
278
|
|
|
286
279
|
Notes
|
|
287
280
|
-----
|
|
288
|
-
If using `'numba'` as the concurrency package, the maximum number of processors is
|
|
289
|
-
|
|
290
|
-
|
|
281
|
+
If using `'numba'` as the concurrency package, the maximum number of processors is retrieved from
|
|
282
|
+
`numba.get_num_threads()` rather than by polling the hardware. If Numba environment variables limit available
|
|
283
|
+
processors, that will affect this function.
|
|
291
284
|
|
|
292
|
-
When using Numba, this function must be called before importing any Numba-jitted
|
|
293
|
-
|
|
285
|
+
When using Numba, this function must be called before importing any Numba-jitted function for this processor limit
|
|
286
|
+
to affect the Numba-jitted function.
|
|
294
287
|
"""
|
|
295
288
|
if not (CPUlimit is None or isinstance(CPUlimit, (bool, int, float))):
|
|
296
289
|
CPUlimit = oopsieKwargsie(CPUlimit)
|
|
@@ -312,9 +305,9 @@ def validateListDimensions(listDimensions: Sequence[int]) -> tuple[int, ...]:
|
|
|
312
305
|
"""
|
|
313
306
|
Validate and normalize dimensions for a map folding problem.
|
|
314
307
|
|
|
315
|
-
This function serves as the gatekeeper for dimension inputs, ensuring that all
|
|
316
|
-
|
|
317
|
-
|
|
308
|
+
This function serves as the gatekeeper for dimension inputs, ensuring that all map dimensions provided to the
|
|
309
|
+
package meet the requirements for valid computation. It performs multiple validation steps and normalizes the
|
|
310
|
+
dimensions into a consistent format.
|
|
318
311
|
|
|
319
312
|
Parameters
|
|
320
313
|
----------
|
|
@@ -323,26 +316,39 @@ def validateListDimensions(listDimensions: Sequence[int]) -> tuple[int, ...]:
|
|
|
323
316
|
|
|
324
317
|
Returns
|
|
325
318
|
-------
|
|
326
|
-
|
|
327
|
-
|
|
319
|
+
mapShape
|
|
320
|
+
An _unsorted_ tuple of positive integers representing the validated dimensions.
|
|
328
321
|
|
|
329
322
|
Raises
|
|
330
323
|
------
|
|
331
324
|
ValueError
|
|
332
325
|
If the input is empty or contains negative values.
|
|
333
326
|
NotImplementedError
|
|
334
|
-
If fewer than two positive dimensions are provided
|
|
335
|
-
represent a valid map folding problem.
|
|
327
|
+
If fewer than two positive dimensions are provided.
|
|
336
328
|
"""
|
|
337
329
|
if not listDimensions:
|
|
338
330
|
raise ValueError("`listDimensions` is a required parameter.")
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
for dimension in
|
|
342
|
-
if dimension
|
|
343
|
-
raise ValueError(f"`{dimension = }` in `{listDimensions = }`, must be a non-negative integer.")
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if len(dimensionsValid) < 2:
|
|
331
|
+
listOFint: list[int] = intInnit(listDimensions, 'listDimensions')
|
|
332
|
+
mapDimensions: list[int] = []
|
|
333
|
+
for dimension in listOFint:
|
|
334
|
+
if dimension <= 0:
|
|
335
|
+
raise ValueError(f"I received `{dimension = }` in `{listDimensions = }`, but all dimensions must be a non-negative integer.")
|
|
336
|
+
mapDimensions.append(dimension)
|
|
337
|
+
if len(mapDimensions) < 2:
|
|
347
338
|
raise NotImplementedError(f"This function requires `{listDimensions = }` to have at least two dimensions greater than 0. You may want to look at https://oeis.org/.")
|
|
348
|
-
|
|
339
|
+
|
|
340
|
+
"""
|
|
341
|
+
I previously sorted the dimensions for a few reasons that may or may not be valid:
|
|
342
|
+
1. After empirical testing, I believe that (2,10), for example, computes significantly faster than (10,2).
|
|
343
|
+
2. Standardization, generally.
|
|
344
|
+
3. If I recall correctly, after empirical testing, I concluded that sorted dimensions always leads to
|
|
345
|
+
non-negative values in the connection graph, but if the dimensions are not in ascending order of magnitude,
|
|
346
|
+
the connection graph might have negative values, which as far as I know, is not an inherent problem, but the
|
|
347
|
+
negative values propagate into other data structures, which requires the datatypes to hold negative values,
|
|
348
|
+
which means I cannot optimize the bit-widths of the datatypes as easily. (And optimized bit-widths helps with
|
|
349
|
+
performance.)
|
|
350
|
+
|
|
351
|
+
Furthermore, now that the package includes OEIS A000136, 1 x N stamps/maps, sorting could distort results.
|
|
352
|
+
"""
|
|
353
|
+
# NOTE Do NOT sort the dimensions.
|
|
354
|
+
return tuple(mapDimensions)
|