cache

Module for caching.

The basic concept of caching in Zfit builds on a “cacher”, that caches a certain value and that is dependent of “cache_dependents”. By implementing ZfitCachable, an object will be able to play both roles. And most importantly, it has a _cache dict, that contains all the cache.

Basic principle

A “cacher” adds any dependents that it may comes across with add_cache_dependents. For example, for a loss this would be all pdfs and data. Since Space is immutable, there is no need to add this as a dependent. This leads to the “cache_dependent” to register the “cacher” and to remember it.

In case, any “cache_dependent” changes in a way the cache of itself (and any “cacher”) is invalid, which is done in the simplest case by decorating a method with @invalidates_cache, the “cache_dependent”:

  • clears it’s own cache with reset_cache_self and

  • “clears” any “cacher”s cache with reset_cache(reseter=self), telling the “cacher” that it should reset the cache. This is also where more fine-grained control (depending on which “cache_dependent” calls reset_cache) can be brought into play.

Example with a pdf that caches the normalization:

class Parameter(Cachable):
    def load(new_value):  # does not require to build a new graph
        # do something

    @invalidates_cache
    def change_limits(new_limits):  # requires to build a new graph (as an example)
        # do something

# create param1, param2 from `Parameter`

class MyPDF(Cachable):
    def __init__(self, param1, param2):
        self.add_cache_dependents([param1, param2])

    def cached_func(...):
        if self._cache.get('my_name') is None:
            result = ...  # calculations here
            self._cache['my_name']
        else:
            result = self._cache['my_name']
        return result
class zfit.util.cache.Cachable(*args, **kwargs)[source]

Bases: zfit.util.cache.ZfitCachable

add_cache_dependents(cache_dependents: Union[zfit.core.interfaces.ZfitCachable, Iterable[zfit.core.interfaces.ZfitCachable]], allow_non_cachable: bool = True)[source]

Add dependents that render the cache invalid if they change.

Parameters
  • cache_dependents (ZfitCachable) –

  • allow_non_cachable (bool) – If True, allow cache_dependents to be non-cachables. If False, any cache_dependents that is not a ZfitCachable will raise an error.

Raises

TypeError – if one of the cache_dependents is not a ZfitCachable _and_ allow_non_cachable if False.

graph_caching_methods = []
instances = <_weakrefset.WeakSet object>
register_cacher(cacher: Union[zfit.core.interfaces.ZfitCachable, Iterable[zfit.core.interfaces.ZfitCachable]])[source]

Register a cacher that caches values produces by this instance; a dependent.

Parameters

() (cacher) –

reset_cache(reseter: zfit.util.cache.ZfitCachable)[source]
reset_cache_self()[source]

Clear the cache of self and all dependent cachers.

class zfit.util.cache.FunctionCacheHolder(func, wrapped_func, cachables: Union[zfit.util.cache.ZfitCachable, object, Iterable[Union[zfit.util.cache.ZfitCachable, object]]] = None, cachables_mapping=None)[source]

Bases: zfit.util.cache.Cachable

tf.function decorated function holder with caching dependencies on inputs.

A tf.function creates a new graph for every signature that is encountered. It automatically caches them but thereby assumes that Python objects are immutable. Any mutation won’t be detected. Therefore, an extra wrapper is needed. The input signature is compared with firstly checking whether the function is the same and then doing an equal comparison of the arguments (maybe too costly?).

The FunctionCacheHolder holds the
  • original python function which serves as the hash of the object

  • wrapped python function, wrapped_func

  • the (keyword-)arguments

If any of the keyword arguments changes in a way that the graph cache is invalid, this holder will have is_valid set to False and the wrapped_func cannot be used anymore, instead a new tf.function should be created as a call to the wrapped_func with the given arguments will result in an outdated graph.

Parameters
  • func (function) – Python function that serves as a hash of the holder. Notice that equality is different defined.

  • wrapped_func (tf.function wrapped) – Wrapped func with tf.function. The holder signals via is_valid whether this function is still valid to be used.

  • cachables – objects that are cached. If they change, the cache is invalidated

  • cachables_mapping (Mapping) – keyword arguments to the function. If the values change, the cache is invalidated.

IS_TENSOR = <object object>
add_cache_dependents(cache_dependents: Union[zfit.core.interfaces.ZfitCachable, Iterable[zfit.core.interfaces.ZfitCachable]], allow_non_cachable: bool = True)

Add dependents that render the cache invalid if they change.

Parameters
  • cache_dependents (ZfitCachable) –

  • allow_non_cachable (bool) – If True, allow cache_dependents to be non-cachables. If False, any cache_dependents that is not a ZfitCachable will raise an error.

Raises

TypeError – if one of the cache_dependents is not a ZfitCachable _and_ allow_non_cachable if False.

create_immutable(args, kwargs)[source]

Create a tuple of the args and kwargs by combining them as args + kwargs.keys() + kwargs.values()`

Parameters
  • args – list like

  • kwargs – dict-like

Returns

tuple

graph_caching_methods = []
instances = <_weakrefset.WeakSet object>
register_cacher(cacher: Union[zfit.core.interfaces.ZfitCachable, Iterable[zfit.core.interfaces.ZfitCachable]])

Register a cacher that caches values produces by this instance; a dependent.

Parameters

() (cacher) –

reset_cache(reseter: zfit.util.cache.ZfitCachable)
reset_cache_self()[source]

Clear the cache of self and all dependent cachers.

class zfit.util.cache.ZfitCachable[source]

Bases: object

abstract add_cache_dependents(cache_dependents, allow_non_cachable)[source]

Add dependents that render the cache invalid if they change.

Parameters
  • cache_dependents (ZfitCachable) –

  • allow_non_cachable (bool) – If True, allow cache_dependents to be non-cachables. If False, any cache_dependents that is not a ZfitCachable will raise an error.

Raises

TypeError – if one of the cache_dependents is not a ZfitCachable _and_ allow_non_cachable if False.

abstract register_cacher(cacher: zfit.util.cache.ZfitCachable)[source]
abstract reset_cache(reseter)[source]
abstract reset_cache_self()[source]

Clear the cache of self and all dependent cachers.

zfit.util.cache.clear_graph_cache()[source]
zfit.util.cache.invalidate_graph(func)[source]