11# ruff: noqa: PLC0415 E701
2-
3- """
4- Mathematical validation and discovery through OEIS integration.
5-
6- (AI generated docstring)
7-
8- Complementing the unified computational interface, this module extends the map
9- folding ecosystem into the broader mathematical community through comprehensive
10- integration with the Online Encyclopedia of Integer Sequences (OEIS). This bridge
11- enables validation of computational results against established mathematical
12- knowledge while supporting the discovery of new sequence values through the
13- sophisticated computational assembly line.
14-
15- The integration provides multiple pathways for mathematical verification: direct
16- computation of OEIS sequences using the complete algorithmic implementation,
17- cached access to published sequence data for rapid validation, and research
18- support for extending known sequences through new computational discoveries.
19- The module handles sequence families ranging from simple strip folding to
20- complex multi-dimensional hypercube problems.
21-
22- Through intelligent caching and optimized lookup mechanisms, this module ensures
23- that the computational power developed through the foundational layers can contribute
24- meaningfully to mathematical research. Whether validating results, avoiding
25- redundant computation, or extending mathematical knowledge, this integration
26- completes the journey from configuration foundation to mathematical discovery.
27- """
28-
292from datetime import datetime , timedelta , UTC
3+ from email .utils import format_datetime
4+ from functools import cache
305from hunterMakesPy .filesystemToolkit import writeStringToHere
316from itertools import chain
327from mapFolding import MetadataOEISid , MetadataOEISidMapFolding , packageSettings
3712from os import PathLike
3813from pathlib import Path , PurePath
3914from typing import Final , Literal
40- from urllib .error import HTTPError , URLError
41- from urllib .request import urlopen
4215import argparse
4316import sys
4417import time
18+ import urllib3
4519import warnings
4620
4721def _standardizeOEISid (oeisID : str ) -> str :
@@ -149,22 +123,56 @@ def _getOEISofficial(pathFilenameCache: Path, url: str) -> None | str:
149123
150124 if not tryCache :
151125 if not url .startswith (("http:" , "https:" )):
152- message = "URL must start with 'http:' or 'https:'"
126+ message : str = "URL must start with 'http:' or 'https:'"
153127 raise ValueError (message )
154128
129+ cachedInformation : str | None = None
130+ cacheIsReadable : bool = False
131+ if pathFilenameCache .exists ():
132+ try :
133+ cachedInformation = pathFilenameCache .read_text (encoding = "utf-8" )
134+ cacheIsReadable = True
135+ except OSError :
136+ cacheIsReadable = False
137+
138+ headers : dict [str , str ] | None = None
139+ if cacheIsReadable :
140+ cacheDatetime : datetime = datetime .fromtimestamp (pathFilenameCache .stat ().st_mtime , tz = UTC )
141+ headers = {"If-Modified-Since" : format_datetime (cacheDatetime , usegmt = True )}
142+
143+ httpPoolManager = urllib3 .PoolManager (retries = False )
155144 try :
156- with urlopen (url ) as response : # noqa: S310
157- oeisInformationRaw = response .read ().decode ('utf-8' )
158- oeisInformation = str (oeisInformationRaw )
159- writeStringToHere (oeisInformation , pathFilenameCache )
160- except (HTTPError , URLError ):
161- oeisInformation = pathFilenameCache .read_text (encoding = "utf-8" )
145+ response = httpPoolManager .request (
146+ "GET"
147+ , url
148+ , headers = headers
149+ , preload_content = True
150+ , decode_content = True
151+ )
152+ if response .status == 304 :
153+ oeisInformation = cachedInformation
154+ if cacheIsReadable :
155+ pathFilenameCache .touch ()
156+ elif response .status == 200 :
157+ oeisInformation = response .data .decode ("utf-8" )
158+ if (cachedInformation is not None ) and (oeisInformation == cachedInformation ):
159+ pathFilenameCache .touch ()
160+ else :
161+ writeStringToHere (oeisInformation , pathFilenameCache )
162+ else :
163+ oeisInformation = cachedInformation
164+ except urllib3 .exceptions .HTTPError :
165+ oeisInformation = cachedInformation
166+ finally :
167+ httpPoolManager .clear ()
162168
163169 if not oeisInformation :
164- warnings .warn (f"Failed to retrieve OEIS sequence information for { pathFilenameCache .stem } ." , stacklevel = 2 )
170+ message : str = f"Failed to retrieve OEIS sequence information for { pathFilenameCache .stem } ."
171+ warnings .warn (message , stacklevel = 2 )
165172
166173 return oeisInformation
167174
175+ @cache
168176def getOEISidValues (oeisID : str ) -> dict [int , int ]:
169177 """Retrieve known sequence values for a specified OEIS sequence.
170178
@@ -202,6 +210,7 @@ def getOEISidValues(oeisID: str) -> dict[int, int]:
202210 return _parseBFileOEIS (oeisInformation )
203211 return {- 1 : - 1 }
204212
213+ @cache
205214def getOEISidInformation (oeisID : str ) -> tuple [str , int ]:
206215 """Retrieve the description and offset metadata for an OEIS sequence.
207216
@@ -258,6 +267,8 @@ def getOEISidInformation(oeisID: str) -> tuple[str, int]:
258267 description : str = ' ' .join (listDescriptionDeconstructed )
259268 return description , offset
260269
270+ #======== Dictionaries of OEIS sequence metadata ==============================================================
271+
261272def _makeDictionaryOEISMapFolding () -> dict [str , MetadataOEISidMapFolding ]:
262273 """Construct the comprehensive settings dictionary for all implemented OEIS sequences.
263274
@@ -294,22 +305,27 @@ def _makeDictionaryOEISMapFolding() -> dict[str, MetadataOEISidMapFolding]:
294305 )
295306 return dictionaryOEIS
296307
308+ def _makeDictionaryOEIS () -> dict [str , MetadataOEISid ]:
309+ dictionary : dict [str , MetadataOEISid ] = {}
310+ for oeisID in packageSettings .OEISidManuallySet :
311+ valuesKnownSherpa : dict [int , int ] = getOEISidValues (oeisID )
312+ descriptionSherpa , offsetSherpa = getOEISidInformation (oeisID )
313+ dictionary [oeisID ] = MetadataOEISid (
314+ description = descriptionSherpa ,
315+ offset = offsetSherpa ,
316+ valuesKnown = valuesKnownSherpa ,
317+ valueUnknown = max (valuesKnownSherpa .keys (), default = 0 ) + 1 ,
318+ )
319+ return dictionary
320+
297321dictionaryOEISMapFolding : dict [str , MetadataOEISidMapFolding ] = _makeDictionaryOEISMapFolding ()
298322"""Metadata for each MapFolding OEIS ID."""
299323
300- def makeDictionaryFoldsTotalKnown () -> dict [tuple [int , ...], int ]:
301- """Make a `mapShape` to known `foldsTotal` dictionary.
302-
303- Returns
304- -------
305- dictionaryFoldsTotalKnown : dict[tuple[int, ...], int]
306- A dictionary where keys are tuples representing map shapes and values are the total number
307- of distinct folding patterns for those shapes.
324+ dictionaryOEIS : dict [str , MetadataOEISid ] = _makeDictionaryOEIS ()
308325
309- """
310- return dict (chain .from_iterable (zip (map (oeisIDmetadata ['getMapShape' ], oeisIDmetadata ['valuesKnown' ].keys ())
311- , oeisIDmetadata ['valuesKnown' ].values (), strict = True ) for oeisID , oeisIDmetadata in dictionaryOEISMapFolding .items () if oeisID != 'A007822' ))
326+ #======== getFoldsTotalKnown ==============================================================
312327
328+ @cache
313329def getFoldsTotalKnown (mapShape : tuple [int , ...]) -> int :
314330 """Retrieve the known total number of distinct folding patterns for a given map shape.
315331
@@ -332,6 +348,21 @@ def getFoldsTotalKnown(mapShape: tuple[int, ...]) -> int:
332348 lookupFoldsTotal : dict [tuple [int , ...], int ] = makeDictionaryFoldsTotalKnown ()
333349 return lookupFoldsTotal .get (tuple (mapShape ), 0 )
334350
351+ def makeDictionaryFoldsTotalKnown () -> dict [tuple [int , ...], int ]:
352+ """Make a `mapShape` to known `foldsTotal` dictionary.
353+
354+ Returns
355+ -------
356+ dictionaryFoldsTotalKnown : dict[tuple[int, ...], int]
357+ A dictionary where keys are tuples representing map shapes and values are the total number
358+ of distinct folding patterns for those shapes.
359+
360+ """
361+ return dict (chain .from_iterable (zip (map (oeisIDmetadata ['getMapShape' ], oeisIDmetadata ['valuesKnown' ].keys ())
362+ , oeisIDmetadata ['valuesKnown' ].values (), strict = True ) for oeisID , oeisIDmetadata in dictionaryOEISMapFolding .items () if oeisID != 'A007822' ))
363+
364+ #======== OEIS for n ==============================================================
365+
335366def _formatHelpText () -> str :
336367 """Format comprehensive help text for both command-line and interactive use.
337368
@@ -483,29 +514,17 @@ def getOEISids() -> None:
483514 """
484515 print (_formatHelpText ()) # noqa: T201
485516
486- def _makeDictionaryOEIS () -> dict [str , MetadataOEISid ]:
487- dictionary : dict [str , MetadataOEISid ] = {}
488- for oeisID in packageSettings .OEISidManuallySet :
489- valuesKnownSherpa : dict [int , int ] = getOEISidValues (oeisID )
490- descriptionSherpa , offsetSherpa = getOEISidInformation (oeisID )
491- dictionary [oeisID ] = MetadataOEISid (
492- description = descriptionSherpa ,
493- offset = offsetSherpa ,
494- valuesKnown = valuesKnownSherpa ,
495- valueUnknown = max (valuesKnownSherpa .keys (), default = 0 ) + 1 ,
496- )
497- return dictionary
498-
499- dictionaryOEIS : dict [str , MetadataOEISid ] = _makeDictionaryOEIS ()
500-
501- if __name__ == "__main__" :
502- getOEISids ()
503-
504-
505- def NOTcountingFolds (oeisID : str , oeis_n : int , flow : str | None = None
506- , pathLikeWriteFoldsTotal : PathLike [str ] | PurePath | None = None
507- , CPUlimit : bool | float | int | None = None # noqa: FBT001
508- ) -> int :
517+ # SEMIOTICS `NOTcountingFolds`: improve identifier.
518+
519+ # TODO A long time ago, I had an explicit rule written in "oeis.py" that the module contained only OEIS stuff and ALL OEIS stuff.
520+ # This function is fundamentally an OEIS function, but I have been trying to treat it the same as `countingFolds`. That mismatch
521+ # is a major reason for the many problems I've had with semiotics and flow design. `oeisIDfor_n` _might_ be the correct identifier
522+ # for this function. I created `oeisIDfor_n` a very very very long time ago, and I think my brain might have locked into it being
523+ # a frontend for `countFolds`. I made `oeisIDfor_n` before I had a need for the `flow` parameter. Since creating the `flow`
524+ # parameter, I have been trying to figure out how to put it into `oeisIDfor_n`. For a long time, `oeisIDfor_n` would call numba
525+ # theorem2 because it was the fastest, but I made numba an optional dependency. All of these seemingly unrelated issues underscore
526+ # the importance of the semiotics-first paradigm (for me).
527+ def NOTcountingFolds (oeisID : str , oeis_n : int , flow : str | None = None , pathLikeWriteFoldsTotal : PathLike [str ] | PurePath | None = None , CPUlimit : bool | float | int | None = None ) -> int : # noqa: FBT001
509528 """You can compute the n-th term of specified OEIS sequences using specialized algorithms.
510529
511530 (AI generated docstring)
@@ -748,3 +767,6 @@ def NOTcountingFolds(oeisID: str, oeis_n: int, flow: str | None = None
748767
749768 return countTotal
750769
770+ if __name__ == "__main__" :
771+ getOEISids ()
772+
0 commit comments