
    ph8                        S r SSKrSSKrSSKJrJrJr  SSKrSSKrSSK	J
r
Jr  \" S/ SQ5      rS r " S	 S
\5      r\" 5       4\\\\" S5      1\\\\4S jr0 \
R2                  S4S jr " S S5      rS r\" \
R:                  S   5      rS r " S S5      r S r! " S S\ 5      r" " S S\5      r#SS jr$ " S S\5      r%SS jr&g)z$
Memoization and caching utilities.
    N)
namedtupleupdate_wrapperwraps   )config	constants	CacheInfo)hitsmissescurrsizec                      [         R                  " [        R                  " 5       5      n U R	                  5       [
        R                  :  $ )z4Check if the memory is too full for further caching.)psutilProcessosgetpidmemory_percentr   MAXIMUM_CACHE_MEMORY_PERCENTAGE)current_processs    E/home/james-whalen/.local/lib/python3.13/site-packages/pyphi/cache.pymemory_fullr      s5    nnRYY[1O**,223 4    c                   <   ^  \ rS rSrSrSr\4U 4S jjrS rSr	U =r
$ )
_HashedSeq!   zThis class guarantees that ``hash()`` will be called no more than once
per element.  This is important because the ``lru_cache()`` will hash the
key multiple times on a cache miss.
	hashvaluec                 D   > [         TU ]  5         XS S & U" U5      U l        g N)super__init__r   )selftuphash	__class__s      r   r    _HashedSeq.__init__)   s     Qcr   c                     U R                   $ r   r   r!   s    r   __hash___HashedSeq.__hash__.   s    ~~r   )__name__
__module____qualname____firstlineno____doc__	__slots__r#   r    r(   __static_attributes____classcell__r$   s   @r   r   r   !   s!    
 I!% #
 r   r   c	                 (  ^ U n	U(       a'  U" UR                  5       5      n
X-  n	U
 H  nX-  n	M	     U(       a0  X" U4S jU  5       5      -  n	U(       a  X" U4S jW
 5       5      -  n	O U" U	5      S:X  a  T" U	S   5      U;   a  U	S   $ [        U	5      $ )ay  Make a cache key from optionally typed positional and keyword arguments.

The key is constructed in a way that is flat as possible rather than as a
nested structure that would take more memory.

If there is only a single argument and its data type is known to cache its
hash value, then that argument is returned without a wrapper.  This saves
space and improves lookup speed.
c              3   4   >#    U  H  nT" U5      v   M     g 7fr    ).0vtypes     r   	<genexpr>_make_key.<locals>.<genexpr>F   s     +dT!WWds   c              3   8   >#    U  H  u  pT" U5      v   M     g 7fr   r5   )r6   kr7   r8   s      r   r9   r:   H   s     :\TQa\s   r   r   )itemsr   )argskwdstypedkwd_mark	fasttypessortedtupler8   lenkeysorted_itemsitems          `    r   	_make_keyrI   2   s     Cdjjl+ DKC !u+d+++5:\:::C	SQ4A<941vc?r   Fc                 H   ^ ^^^^ [        5       m[        mSU UUUU4S jjnU$ )a<  Memory-limited cache decorator.

``maxmem`` is a float between 0 and 100, inclusive, specifying the maximum
percentage of physical memory that the cache can use.

If ``typed`` is ``True``, arguments of different types will be cached
separately. For example, f(3.0) and f(3) will be treated as distinct calls
with distinct results.

Arguments to the cached function must be hashable.

View the cache statistics named tuple (hits, misses, currsize)
with f.cache_info(). Clear the cache and statistics with f.cache_clear().
Access the underlying function with f.__wrapped__.
c           	         >^ ^^^^ SmTR                   mT
(       d  UUUU	UUUU 4S jnOUUUUU	U
UUU 4	S jnUUU4S jnUUUU4S jnXCl        XSl        [        UT 5      $ )NFc                  h   > T" XT
5      nT" UT	5      nUT	La  TS-  mU$ T" U 0 UD6nUTU'   TS-  mU$ Nr   r5   )r>   r?   rF   resultcache	cache_getr
   make_keyr   sentinelr@   user_functions       r   wrapper3cache.<locals>.decorating_function.<locals>.wrapperl   sY     t51"31)AID!M&55#c
!r   c                     >	 T	" XT5      nT" U5      nUb  TS-  mU$ T" U 0 UD6nT(       dA  UTU'   [         R                  " [        R                  " 5       5      nUR	                  5       T
:  mTS-  mU$ rM   )r   r   r   r   r   )r>   r?   rF   rN   r   rO   rP   fullr
   rQ   maxmemr   r@   rS   s        r   rT   rU   {   s     t51"3%AID!M&55!'E#J '-nnRYY[&AO*99;fDD!r   c                  0   > [        TT[        T 5      5      $ )zReport cache statistics.)
_CacheInforE   rO   r
   r   s   r   
cache_info6cache.<locals>.decorating_function.<locals>.cache_info   s    dFCJ77r   c                  2   > T R                  5         S=mmSmg)z%Clear the cache and cache statistics.r   FN)clear)rO   rW   r
   r   s   r   cache_clear7cache.<locals>.decorating_function.<locals>.cache_clear   s     KKMD6Dr   )getr\   r`   r   )rS   r
   r   rT   r\   r`   rP   rW   rO   rQ   rX   rR   r@   s   ```   @@r   decorating_function"cache.<locals>.decorating_functione   sR    II	  $	8	 	 ()g}55r   )r   r   )objectrI   )rO   rX   r@   rc   rQ   rR   s   ``` @@r   rO   rO   N   s$    & xHH56 56n r   c                   J    \ rS rSrSrS rS rS rS rS r	S r
S	S
.S jrSrg	)	DictCache   zcA generic dictionary-based cache.

Intended to be used as an object-level cache of method results.
c                 .    0 U l         SU l        SU l        g Nr   r[   r'   s    r   r    DictCache.__init__       
	r   c                 .    0 U l         SU l        SU l        g rj   r[   r'   s    r   r_   DictCache.clear   rl   r   c                 ,    [        U R                  5      $ )zNumber of items in cache)rE   rO   r'   s    r   sizeDictCache.size   s    4::r   c                 `    [        U R                  U R                  U R                  5       5      $ )z.Return info about cache hits, misses, and size)rZ   r
   r   rp   r'   s    r   infoDictCache.info   s    $))T[[$))+>>r   c                     XR                   ;   a$  U =R                  S-  sl        U R                   U   $ U =R                  S-  sl        g)zfGet a value out of the cache.

Returns None if the key is not in the cache. Updates cache
statistics.
r   Nr[   )r!   rF   s     r   rb   DictCache.get   s:     **IINI::c?"qr   c                      X R                   U'   g)zSet a value in the cacheN)rO   r!   rF   values      r   setDictCache.set   s    

3r   N)_prefixc                D    U(       a  [        S5      eU4[        U5      -   $ )zdGet the cache key for the given function args.

Kwargs:
   prefix: A constant to prefix to the key.
z kwarg cache keys not implemented)NotImplementedErrorrD   )r!   r|   r>   kwargss       r   rF   DictCache.key   s(     %24 4zE$K''r   r[   )r*   r+   r,   r-   r.   r    r_   rp   rs   rb   rz   rF   r0   r5   r   r   rg   rg      s4    


?
  "& 	( 	(r   rg   c                 r    [         R                  " [        R                  S   [        R                  S   U S9$ )Nhostport)r   r   db)redisStrictRedisr   REDIS_CONFIG)r   s    r   
redis_initr      s4    &"5"5f"="("5"5f"="F Fr   r   c                  t     [         R                  5       $ ! [        R                  R                   a     gf = f)z'Check if the Redis server is connected.F)
redis_connpingr   
exceptionsConnectionErrorr5   r   r   redis_availabler      s2      ++ s    77c                   B    \ rS rSrS r\S 5       rS rS rS r	S r
Srg	)

RedisCache   c                 T    [         R                  5         [         R                  5         g)zFlush the cache.N)r   flushdbconfig_resetstatr'   s    r   r_   RedisCache.clear   s    ##%r   c                  *    [         R                  5       $ )zSSize of the Redis cache.

.. note:: This is the size of the entire Redis database.
)r   dbsizer5   r   r   rp   RedisCache.size   s       ""r   c                 l    [         R                  5       n[        US   US   U R                  5       5      $ )z`Return cache information.

.. note:: This is not the cache info for the entire Redis key space.
keyspace_hitskeyspace_misses)r   rs   rZ   rp   )r!   rs   s     r   rs   RedisCache.info   s6    
  $/01))+' 	'r   c                 b    [         R                  U5      nUb  [        R                  " U5      nU$ )zJGet a value from the cache.

Returns None if the key is not in the cache.
)r   rb   pickleloadsrx   s      r   rb   RedisCache.get  s+    
 s#LL'Er   c                 t    [         R                  " U[        R                  S9n[        R                  X5        g)zSet a value in the cache.)protocolN)r   dumpsr   PICKLE_PROTOCOLr   rz   rx   s      r   rz   RedisCache.set  s$    UY-F-FGs"r   c                     [         e)zDelegate to subclasses.)r~   r'   s    r   rF   RedisCache.key  s    !!r   r5   N)r*   r+   r,   r-   r_   staticmethodrp   rs   rb   rz   rF   r0   r5   r   r   r   r      s/    &
 # #'
#
"r   r   c                 P    U R                   R                  (       a  [        S5      eg )Nz,parent_cache must be from an uncut subsystem)	subsystemis_cut
ValueErrorparent_caches    r   validate_parent_cacher     s$     $$GHH %r   c                   R   ^  \ rS rSrSrSU 4S jjrU 4S jrU 4S jrS	S jrSr	U =r
$ )
RedisMICECachei"  zRA Redis-backed cache for |Subsystem.find_mice()|.

See |MICECache| for more info.
c                    > [         TU ]  5         Xl        [        U5      U l        Ub  [        U5        UR                  U l        g S U l        g r   )r   r    r   r#   subsystem_hashr   parent_subsystem_hashr!   r   r   r$   s      r   r    RedisMICECache.__init__(  sE    ""9o#!,/ *6)D)DD&)-D&r   c                 *  > [         TU ]  U5      nUb  U$ U R                  (       am  UR                  [	        U R
                  5      [	        U R                  5      S5      n[         TU ]  U5      nUb"  UR                  U R                  5      (       d  U$ g)zoGet a value from the cache.

If the |MICE| cannot be found in this cache, try and find it in the
parent cache.
Nr   )r   rb   r   replacestrr   damaged_by_cutr   )r!   rF   mice
parent_keyr$   s       r   rb   RedisMICECache.get8  s     w{3K %%S)<)<%=%()C)C%DaIJ7;z*D(;(;DNN(K(Kr   c                 \   > U R                   R                  (       d  [        TU ]  X5        gg)z^Only need to set if the subsystem is uncut.

Caches are only inherited from uncut subsystems.
N)r   r   r   rz   )r!   rF   ry   r$   s      r   rz   RedisMICECache.setN  s#    
 ~~$$GK# %r   c                 <    SR                  U R                  XAX#5      $ )ACache key. This is the call signature of |Subsystem.find_mice()|.zsubsys:{}:{}:{}:{}:{})formatr   r!   	direction	mechanismpurviewsr|   s        r   rF   RedisMICECache.keyV  s$    &--YJ 	Jr   )r   r   r   r   FN)r*   r+   r,   r-   r.   r    rb   rz   rF   r0   r1   r2   s   @r   r   r   "  s#    
. ,$J Jr   r   c                   F   ^  \ rS rSrSrSU 4S jjrS rS rS	S jrSr	U =r
$ )
DictMICECachei\  zLA subsystem-local cache for |MICE| objects.

See |MICECache| for more info.
c                 n   > [         TU ]  5         Xl        Ub  [        U5        U R	                  U5        g g r   )r   r    r   r   _buildr   s      r   r    DictMICECache.__init__b  s2    "#!,/KK% $r   c                     UR                   R                  5        H5  u  p#UR                  U R                  5      (       a  M'  X0R                   U'   M7     g)zBuild the initial cache from the parent.

Only include the |MICE| which are unaffected by the subsystem cut.
A |MICE| is affected if either the cut splits the mechanism
or splits the connections between the purview and mechanism
N)rO   r=   r   r   )r!   r   rF   r   s       r   r   DictMICECache._buildj  s?     &++113IC&&t~~66"&

3 4r   c                     U R                   R                  (       d0  UR                  S:  a  [        5       (       d  X R                  U'   gggg)a  Set a value in the cache.

Only cache if:
  - The subsystem is uncut (caches are only inherited from
    uncut subsystems so there is no reason to cache on cut
    subsystems.)
  - |small_phi| > 0. Ideally we would cache all mice, but the size
    of the cache grows way too large, making parallel computations
    incredibly inefficient because the caches have to be passed
    between process. This will be changed once global caches are
    implemented.
  - Memory is not too full.
r   N)r   r   phir   rO   )r!   rF   r   s      r   rz   DictMICECache.setu  s:     %%$((Q,MM"JJsO " +7%r   c                 
    XAX#4$ )r   r5   r   s        r   rF   DictMICECache.key  s    I88r   )r   r   r   )r*   r+   r,   r-   r.   r    r   rz   rF   r0   r1   r2   s   @r   r   r   \  s!    
&	'#$9 9r   r   c                 R    [         R                  (       a  [        nO[        nU" XS9$ )a  Construct a |MICE| cache.

Uses either a Redis-backed cache or a local dict cache on the object.

Args:
    subsystem (Subsystem): The subsystem that this is a cache for.

Kwargs:
    parent_cache (MICECache): The cache generated by the uncut
        version of ``subsystem``. Any cached |MICE| which are
        unaffected by the cut are reused in this cache. If None,
        the cache is initialized empty.
r   )r   REDIS_CACHEr   r   )r   r   clss      r   	MICECacher     s"     y44r   c                       \ rS rSrSrS rSrg)PurviewCachei  z,A network-level cache for possible purviews.c                 L    [         R                  (       a  X R                  U'   gg)z&Only set if purview caching is enabledN)r   CACHE_POTENTIAL_PURVIEWSrO   rx   s      r   rz   PurviewCache.set  s    **#JJsO +r   r5   N)r*   r+   r,   r-   r.   rz   r0   r5   r   r   r   r     s
    6$r   r   c                    ^ ^ U U4S jnU$ )at  Caching decorator for object-level method caches.

Cache key generation is delegated to the cache.

Args:
    cache_name (str): The name of the (already-instantiated) cache
        on the decorated object which should be used to store results
        of this method.
    *key_prefix: A constant to use as part of the cache key in addition
        to the method arguments.
c                    >^  T R                   S;   a  [        R                  (       d  T $ [        T 5      UU U4S j5       nU$ )N)cause_repertoireeffect_repertoirec                    > [        U T5      nUR                  " UST0UD6nUR                  U5      nUc  T" U /UQ70 UD6nUR                  XE5        U$ )Nr|   )getattrrF   rb   rz   )	objr>   r   rO   rF   ry   
cache_namefunc
key_prefixs	         r   rT   *method.<locals>.decorator.<locals>.wrapper  sb    C,E ))T@:@@C IIcNE}S24262		#%Lr   )r*   r   CACHE_REPERTOIRESr   )r   rT   r   r   s   ` r   	decoratormethod.<locals>.decorator  s;    MMFF,,K	t	 
	 r   r5   )r   r   r   s   `` r   methodr     s    ( r   r   )'r.   r   r   	functoolsr   r   r   r   r    r   r   rZ   r   listr   re   intr   	frozensetr8   rC   rD   rE   rI   r   rO   rg   r   r   r   r   r   r   r   r   r   r   r   r5   r   r   <module>r      s   
 
  7 7   %CD
4 $ {c9d4j95t8 6AANb3( 3(lF ++D12
," ,"^I7JZ 7Jt-9I -9`5*$9 $ r   