mapFolding 0.2.2__py3-none-any.whl → 0.2.4__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.
tests/test_other.py CHANGED
@@ -1,13 +1,14 @@
1
- from pathlib import Path
2
- from typing import List
3
- from .conftest import *
1
+ import pathlib
2
+ from tests.conftest import *
3
+ from tests.pythons_idiotic_namespace import *
4
+ from typing import List, Optional
5
+ import itertools
6
+ import numba
7
+ import numpy
4
8
  import pytest
9
+ import random
5
10
  import sys
6
11
  import unittest.mock
7
- import numpy
8
- import numba
9
-
10
- # TODO test `outfitFoldings`; no negative values in arrays; compare datatypes to the typeddict; commpare the connection graph to making a graPH
11
12
 
12
13
  @pytest.mark.parametrize("listDimensions,expected_intInnit,expected_parseListDimensions,expected_validateListDimensions,expected_getLeavesTotal", [
13
14
  (None, ValueError, ValueError, ValueError, ValueError), # None instead of list
@@ -59,18 +60,34 @@ def test_getLeavesTotal_edge_cases() -> None:
59
60
  standardComparison(6, getLeavesTotal, listOriginal)
60
61
  standardComparison([2, 3], lambda x: x, listOriginal) # Check that the list wasn't modified
61
62
 
62
- def test_countFolds_writeFoldsTotal_file(listDimensionsTestFunctionality: List[int], pathFilenameFoldsTotalTesting: Path) -> None:
63
- with unittest.mock.patch("mapFolding.babbage._countFolds", return_value=12345):
64
- standardComparison(12345, countFolds, listDimensionsTestFunctionality, pathFilenameFoldsTotalTesting)
65
- standardComparison("12345", lambda: pathFilenameFoldsTotalTesting.read_text())
63
+ @pytest.mark.parametrize("foldsValue,writeFoldsTarget", [
64
+ (756839, "foldsTotalTest.txt"), # Direct file
65
+ (2640919, "foldsTotalTest.txt"), # Direct file
66
+ (7715177, None), # Directory, will use default filename
67
+ ])
68
+ def test_countFolds_writeFoldsTotal(
69
+ listDimensionsTestFunctionality: List[int],
70
+ pathTempTesting: pathlib.Path,
71
+ mockFoldingFunction,
72
+ foldsValue: int,
73
+ writeFoldsTarget: Optional[str]
74
+ ) -> None:
75
+ """Test writing folds total to either a file or directory."""
76
+ # For directory case, use the directory path directly
77
+ if writeFoldsTarget is None:
78
+ pathWriteTarget = pathTempTesting
79
+ filenameFoldsTotalExpected = getFilenameFoldsTotal(listDimensionsTestFunctionality)
80
+ else:
81
+ pathWriteTarget = pathTempTesting / writeFoldsTarget
82
+ filenameFoldsTotalExpected = writeFoldsTarget
83
+
84
+ mock_countFolds = mockFoldingFunction(foldsValue, listDimensionsTestFunctionality)
66
85
 
67
- def test_countFolds_writeFoldsTotal_directory(listDimensionsTestFunctionality: List[int], pathTempTesting: Path) -> None:
68
- with unittest.mock.patch("mapFolding.babbage._countFolds", return_value=67890):
69
- returned = countFolds(listDimensionsTestFunctionality, writeFoldsTotal=pathTempTesting)
70
- standardComparison(67890, lambda: returned)
71
- # Construct expected filename from sorted dimensions
72
- expectedName = str(sorted(listDimensionsTestFunctionality)).replace(' ', '') + '.foldsTotal'
73
- standardComparison("67890", lambda: (pathTempTesting / expectedName).read_text())
86
+ with unittest.mock.patch("mapFolding.babbage._countFolds", side_effect=mock_countFolds):
87
+ returned = countFolds(listDimensionsTestFunctionality, writeFoldsTotal=pathWriteTarget)
88
+
89
+ standardComparison(foldsValue, lambda: returned) # Check return value
90
+ standardComparison(str(foldsValue), lambda: (pathTempTesting / filenameFoldsTotalExpected).read_text()) # Check file content
74
91
 
75
92
  def test_intInnit() -> None:
76
93
  """Test integer parsing using the test suite generator."""
@@ -82,18 +99,19 @@ def test_oopsieKwargsie() -> None:
82
99
  for testName, testFunction in makeTestSuiteOopsieKwargsie(oopsieKwargsie).items():
83
100
  testFunction()
84
101
 
85
- # TODO mock CPU counts?
86
- # @pytest.mark.parametrize("CPUlimit, expectedLimit", [
87
- # (None, numba.config.NUMBA_DEFAULT_NUM_THREADS),
88
- # (False, numba.config.NUMBA_DEFAULT_NUM_THREADS),
89
- # (True, 1),
90
- # (4, 4),
91
- # (0.5, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS // 2)),
92
- # (-0.5, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS // 2)),
93
- # (-2, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS - 2)),
94
- # ])
95
- # def test_setCPUlimit(CPUlimit, expectedLimit) -> None:
96
- # standardComparison(expectedLimit, setCPUlimit, CPUlimit)
102
+ @pytest.mark.parametrize("CPUlimit, expectedLimit", [
103
+ (None, numba.config.NUMBA_DEFAULT_NUM_THREADS), # type: ignore
104
+ (False, numba.config.NUMBA_DEFAULT_NUM_THREADS), # type: ignore
105
+ (True, 1),
106
+ (4, 4),
107
+ (0.5, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS // 2)), # type: ignore
108
+ (-0.5, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS // 2)), # type: ignore
109
+ (-2, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS - 2)), # type: ignore
110
+ (0, numba.config.NUMBA_DEFAULT_NUM_THREADS), # type: ignore
111
+ (1, 1),
112
+ ])
113
+ def test_setCPUlimit(CPUlimit, expectedLimit) -> None:
114
+ standardComparison(expectedLimit, setCPUlimit, CPUlimit)
97
115
 
98
116
  def test_makeConnectionGraph_nonNegative(listDimensionsTestFunctionality: List[int]) -> None:
99
117
  connectionGraph = makeConnectionGraph(listDimensionsTestFunctionality)
@@ -103,3 +121,148 @@ def test_makeConnectionGraph_nonNegative(listDimensionsTestFunctionality: List[i
103
121
  def test_makeConnectionGraph_datatype(listDimensionsTestFunctionality: List[int], datatype) -> None:
104
122
  connectionGraph = makeConnectionGraph(listDimensionsTestFunctionality, datatype=datatype)
105
123
  assert connectionGraph.dtype == datatype, f"Expected datatype {datatype}, but got {connectionGraph.dtype}."
124
+
125
+
126
+ """5 parameters
127
+ listDimensionsTestFunctionality
128
+
129
+ computationDivisions
130
+ None
131
+ random: int, first included: 2, first excluded: leavesTotal
132
+ maximum
133
+ cpu
134
+
135
+ CPUlimit
136
+ None
137
+ True
138
+ False
139
+ 0
140
+ 1
141
+ -1
142
+ random: 0 < float < 1
143
+ random: -1 < float < 0
144
+ random: int, first included: 2, first excluded: (min(leavesTotal, 16) - 1)
145
+ random: int, first included: -1 * (min(leavesTotal, 16) - 1), first excluded: -1
146
+
147
+ datatypeDefault
148
+ None
149
+ numpy.int64
150
+ numpy.intc
151
+ numpy.uint16
152
+
153
+ datatypeLarge
154
+ None
155
+ numpy.int64
156
+ numpy.intp
157
+ numpy.uint32
158
+
159
+ """
160
+
161
+ @pytest.fixture
162
+ def parameterIterator():
163
+ """Generate random combinations of parameters for outfitCountFolds testing."""
164
+ parameterSets = {
165
+ 'computationDivisions': [
166
+ None,
167
+ 'maximum',
168
+ 'cpu',
169
+ ],
170
+ 'CPUlimit': [
171
+ None, True, False, 0, 1, -1,
172
+ ],
173
+ 'datatypeDefault': [
174
+ None,
175
+ numpy.int64,
176
+ numpy.intc,
177
+ numpy.uint16
178
+ ],
179
+ 'datatypeLarge': [
180
+ None,
181
+ numpy.int64,
182
+ numpy.intp,
183
+ numpy.uint32
184
+ ]
185
+ }
186
+
187
+ def makeParametersDynamic(listDimensions):
188
+ """Add context-dependent parameter values."""
189
+ parametersDynamic = parameterSets.copy()
190
+ leavesTotal = getLeavesTotal(listDimensions)
191
+ concurrencyLimit = min(leavesTotal, 16)
192
+
193
+ # Add dynamic computationDivisions
194
+ parametersDynamic['computationDivisions'].extend(
195
+ [random.randint(2, leavesTotal-1) for iterator in range(3)]
196
+ )
197
+
198
+ # Add dynamic CPUlimit values
199
+ parameterDynamicCPU = [
200
+ random.random(), # 0 to 1
201
+ -random.random(), # -1 to 0
202
+ ]
203
+ parameterDynamicCPU.extend(
204
+ [random.randint(2, concurrencyLimit-1) for iterator in range(2)]
205
+ )
206
+ parameterDynamicCPU.extend(
207
+ [random.randint(-concurrencyLimit+1, -2) for iterator in range(2)]
208
+ )
209
+ parametersDynamic['CPUlimit'].extend(parameterDynamicCPU)
210
+
211
+ return parametersDynamic
212
+
213
+ def generateCombinations(listDimensions):
214
+ parametersDynamic = makeParametersDynamic(listDimensions)
215
+ parameterKeys = list(parametersDynamic.keys())
216
+ parameterValues = [parametersDynamic[key] for key in parameterKeys]
217
+
218
+ # Shuffle each parameter list
219
+ for valueList in parameterValues:
220
+ random.shuffle(valueList)
221
+
222
+ # Use zip_longest to iterate, filling with None when shorter lists are exhausted
223
+ for combination in itertools.zip_longest(*parameterValues, fillvalue=None):
224
+ yield dict(zip(parameterKeys, combination))
225
+
226
+ return generateCombinations
227
+
228
+ def test_outfitCountFolds_basic(listDimensionsTestFunctionality, parameterIterator):
229
+ """Basic validation of outfitCountFolds return value structure."""
230
+ parameters = next(parameterIterator(listDimensionsTestFunctionality))
231
+
232
+ stateInitialized = outfitCountFolds(
233
+ listDimensionsTestFunctionality,
234
+ **{k: v for k, v in parameters.items() if v is not None}
235
+ )
236
+
237
+ # Basic structure tests
238
+ assert isinstance(stateInitialized, dict)
239
+ assert len(stateInitialized) == 7 # 6 ndarray + 1 tuple
240
+
241
+ # Check for specific keys
242
+ requiredKeys = set(computationState.__annotations__.keys())
243
+ assert set(stateInitialized.keys()) == requiredKeys
244
+
245
+ # Check types more carefully
246
+ for key, value in stateInitialized.items():
247
+ if key == 'mapShape':
248
+ assert isinstance(value, tuple)
249
+ assert all(isinstance(dim, int) for dim in value)
250
+ else:
251
+ assert isinstance(value, numpy.ndarray), f"{key} should be ndarray but is {type(value)}"
252
+ assert issubclass(value.dtype.type, numpy.integer), \
253
+ f"{key} should have integer dtype but has {value.dtype}"
254
+
255
+ def test_pathJobDEFAULT_colab():
256
+ """Test that pathJobDEFAULT is set correctly when running in Google Colab."""
257
+ # Mock sys.modules to simulate running in Colab
258
+ with unittest.mock.patch.dict('sys.modules', {'google.colab': unittest.mock.MagicMock()}):
259
+ # Force reload of theSSOT to trigger Colab path logic
260
+ import importlib
261
+ import mapFolding.theSSOT
262
+ importlib.reload(mapFolding.theSSOT)
263
+
264
+ # Check that path was set to Colab-specific value
265
+ assert mapFolding.theSSOT.pathJobDEFAULT == pathlib.Path("/content/drive/MyDrive") / "jobs"
266
+
267
+ # Reload one more time to restore original state
268
+ importlib.reload(mapFolding.theSSOT)
@@ -0,0 +1,25 @@
1
+ from tests.conftest import *
2
+ from typing import Dict, List, Tuple
3
+ import importlib
4
+ import pytest
5
+
6
+ @pytest.fixture(scope="session", autouse=True)
7
+ def runSecondSetAfterAll(request: pytest.FixtureRequest):
8
+ """Run after all other tests complete."""
9
+ def toggleAndRerun():
10
+ import mapFolding.importSelector
11
+ import mapFolding.babbage
12
+ mapFolding.importSelector.useLovelace = not mapFolding.importSelector.useLovelace
13
+ importlib.reload(mapFolding.importSelector)
14
+ importlib.reload(mapFolding.babbage)
15
+
16
+ request.addfinalizer(toggleAndRerun)
17
+
18
+ @pytest.mark.order(after="runSecondSetAfterAll")
19
+ def test_myabilitytodealwithbs(oeisID: str):
20
+ for n in settingsOEIS[oeisID]['valuesTestValidation']:
21
+ standardComparison(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
22
+
23
+ @pytest.mark.order(after="runSecondSetAfterAll")
24
+ def test_eff_em_el(listDimensionsTest_countFolds: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int]) -> None:
25
+ standardComparison(foldsTotalKnown[tuple(listDimensionsTest_countFolds)], countFolds, listDimensionsTest_countFolds, None, 'maximum')
@@ -1,74 +0,0 @@
1
- from ...tests.conftest import *
2
- from .benchmarking import recordBenchmarks, runBenchmarks
3
- import numpy
4
- import pathlib
5
- import pytest
6
- import unittest.mock
7
- from typing import List
8
-
9
- def test_recordBenchmarks_decorator(pathBenchmarksTesting: pathlib.Path,
10
- listDimensionsTestFunctionality: List[int],
11
- mockBenchmarkTimer: unittest.mock.MagicMock):
12
- """Test that the decorator correctly records benchmark data."""
13
- @recordBenchmarks()
14
- def functionTest(listDimensions: List[int]) -> int:
15
- return sum(listDimensions)
16
-
17
- with mockBenchmarkTimer:
18
- mockBenchmarkTimer.side_effect = [0, 1e9]
19
- result = functionTest(listDimensionsTestFunctionality)
20
-
21
- # Verify function still works normally
22
- assert result == sum(listDimensionsTestFunctionality)
23
-
24
- # Verify benchmark data was saved
25
- arrayBenchmarks = numpy.load(str(pathBenchmarksTesting), allow_pickle=True)
26
- assert len(arrayBenchmarks) == 1
27
- assert arrayBenchmarks[0]['time'] == 1.0
28
- assert tuple(arrayBenchmarks[0]['dimensions']) == tuple(listDimensionsTestFunctionality)
29
-
30
- def test_recordBenchmarks_multiple_calls(pathBenchmarksTesting: pathlib.Path,
31
- listDimensionsTestFunctionality: List[int],
32
- mockBenchmarkTimer: unittest.mock.MagicMock):
33
- """Test that multiple function calls append to benchmark data."""
34
- @recordBenchmarks()
35
- def functionTest(listDimensions: List[int]) -> int:
36
- return sum(listDimensions)
37
-
38
- with mockBenchmarkTimer:
39
- mockBenchmarkTimer.side_effect = [0, 1e9, 2e9, 4e9]
40
- functionTest(listDimensionsTestFunctionality)
41
- functionTest(listDimensionsTestFunctionality)
42
-
43
- arrayBenchmarks = numpy.load(str(pathBenchmarksTesting), allow_pickle=True)
44
- assert len(arrayBenchmarks) == 2
45
- assert arrayBenchmarks[0]['time'] == 1.0
46
- assert arrayBenchmarks[1]['time'] == 2.0
47
-
48
- # NOTE This test tries to collect benchmark data without ensuring that a function is decorated.
49
- # def test_runBenchmarks_integration(pathBenchmarksTesting: pathlib.Path, listDimensionsTestFunctionality: List[int]):
50
- # """Test runBenchmarks creates valid benchmark data."""
51
- # countIterations = 2
52
- # runBenchmarks(countIterations)
53
-
54
- # arrayBenchmarks = numpy.load(str(pathBenchmarksTesting), allow_pickle=True)
55
- # assert len(arrayBenchmarks) > 0 # Should have recorded some benchmarks
56
-
57
- # # Verify data structure integrity
58
- # assert arrayBenchmarks.dtype.names == ('time', 'dimensions')
59
- # assert all(isinstance(record['time'], float) for record in arrayBenchmarks)
60
- # assert all(isinstance(record['dimensions'], tuple) for record in arrayBenchmarks)
61
-
62
- # # Verify at least one benchmark entry matches our test dimensions
63
- # assert any(tuple(listDimensionsTestFunctionality) == record['dimensions'] for record in arrayBenchmarks)
64
-
65
- # NOTE This test tries to collect benchmark data without ensuring that a function is decorated.
66
- # @pytest.mark.parametrize("countIterations", [1, 2])
67
- # def test_runBenchmarks_iterations(countIterations: int, pathBenchmarksTesting: pathlib.Path, listDimensionsTestFunctionality: List[int]):
68
- # """Test runBenchmarks records data for each iteration."""
69
- # runBenchmarks(countIterations)
70
- # arrayBenchmarks = numpy.load(str(pathBenchmarksTesting), allow_pickle=True)
71
-
72
- # # Should have at least countIterations entries for our test dimensions
73
- # countMatches = sum(1 for record in arrayBenchmarks if tuple(listDimensionsTestFunctionality) == record['dimensions'])
74
- # assert countMatches >= countIterations
@@ -1,28 +0,0 @@
1
- mapFolding/__init__.py,sha256=POxXTSE6Qu1G8k-YlSXHzbe-_JGuHk-L9p5SLRng4vA,439
2
- mapFolding/babbage.py,sha256=3D1qcntoiJm2tqgbiCAMc7GpGA0SZTdGORNEnensyxk,1882
3
- mapFolding/beDRY.py,sha256=ZrUXCNqnumTQ1XX8RT5gGdRr-a-o8QxEiGrerUxKtYg,12784
4
- mapFolding/lovelace.py,sha256=qcyGpVEPP3n0r-RNrSUgPRP3yZJfBEfmok7jYMm1OI0,11473
5
- mapFolding/oeis.py,sha256=_-fLGc1ybZ2eFxoiBrSmojMexeg6ROxtrLaBF2BzMn4,12144
6
- mapFolding/startHere.py,sha256=RGdFoJJdrJ_0tmLIKZn1WnHP0NCZwvQG7C2p4EUHOe4,5034
7
- mapFolding/theSSOT.py,sha256=yRW6aHyJxheL-Znk537LQA6xUPHz6FfoXY-0Ayh3Lsg,2178
8
- mapFolding/JAX/lunnanJAX.py,sha256=xMZloN47q-MVfjdYOM1hi9qR4OnLq7qALmGLMraevQs,14819
9
- mapFolding/JAX/taskJAX.py,sha256=yJNeH0rL6EhJ6ppnATHF0Zf81CDMC10bnPnimVxE1hc,20037
10
- mapFolding/benchmarks/benchmarking.py,sha256=kv85F6V9pGhZvTOImArOuxyg5rywA_T6JLH_qFXM8BM,3018
11
- mapFolding/benchmarks/test_benchmarks.py,sha256=c4ANeR3jgqpKXFoxDeZkmAHxSuenMwsjmrhKJ1_XPqY,3659
12
- mapFolding/reference/hunterNumba.py,sha256=0giUyqAFzP-XKcq3Kz8wIWCK0BVFhjABVJ1s-w4Jhu0,7109
13
- mapFolding/reference/irvineJavaPort.py,sha256=Sj-63Z-OsGuDoEBXuxyjRrNmmyl0d7Yz_XuY7I47Oyg,4250
14
- mapFolding/reference/lunnan.py,sha256=XEcql_gxvCCghb6Or3qwmPbn4IZUbZTaSmw_fUjRxZE,5037
15
- mapFolding/reference/lunnanNumpy.py,sha256=HqDgSwTOZA-G0oophOEfc4zs25Mv4yw2aoF1v8miOLk,4653
16
- mapFolding/reference/lunnanWhile.py,sha256=7NY2IKO5XBgol0aWWF_Fi-7oTL9pvu_z6lB0TF1uVHk,4063
17
- mapFolding/reference/rotatedEntryPoint.py,sha256=z0QyDQtnMvXNj5ntWzzJUQUMFm1-xHGLVhtYzwmczUI,11530
18
- mapFolding/reference/total_countPlus1vsPlusN.py,sha256=usenM8Yn_G1dqlPl7NKKkcnbohBZVZBXTQRm2S3_EDA,8106
19
- tests/__init__.py,sha256=PGYVr7r23gATgcvZ3Sfph9D_g1MVvhgzMNWXBs_9tmY,52
20
- tests/conftest.py,sha256=VFYSd7-tHWd-LUKnTY24PIJhq9quP9S3sK2SYusNNog,12875
21
- tests/test_oeis.py,sha256=vxnwO-cSR68htkyMh9QMVv-lvxBo6qlwPg1Rbx4JylY,7963
22
- tests/test_other.py,sha256=cf8DbkZxm_DHNq9lkMe7auXye_XspruU9qiNZATkxr4,6930
23
- tests/test_tasks.py,sha256=Nwe4iuSjwGZvsw5CXCcic7tkBxgM5JX9mrGZMDYhAwE,1785
24
- mapFolding-0.2.2.dist-info/METADATA,sha256=BSCXcKZDhAtOWr8A5pZMG8bZnm5YBLf-6uMN9qs8JDk,5914
25
- mapFolding-0.2.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
26
- mapFolding-0.2.2.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
27
- mapFolding-0.2.2.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
28
- mapFolding-0.2.2.dist-info/RECORD,,