Source code for iwopy.core.memory

import numpy as np


def get_default_keyf(digits=12):
    """
    Get the default key function

    Parameters
    ----------
    digits: int
        The number of digits for floats

    Returns
    -------
    Function :
        The default key function
    
    :group: core

    """

    def default_key(vars_int, vars_float):
        """
        Default key function

        Parameters
        ----------
        vars_int: np.array
            The integer variable values, shape: (n_vars_int,)
        vars_float: np.array
            The float variable values, shape: (n_vars_float,)

        Returns
        -------
        Object :
            The key

        """
        li = vars_int.tolist() if len(vars_int) else []
        tf = tuple(tuple(v.tolist()) for v in np.round(vars_float, digits))
        return (tuple(li), tf)

    return default_key


[docs]class Memory: """ Storage for function results. Attributes ---------- max_size: int The number of maximally stored results data: dict The stored data. Key: keyf return type, Values: tuples (objs, cons) keyf: Function The memory key function. Parameters: (vars_int, vars_float), returns key Object :group: core """
[docs] def __init__(self, size, keyf=None): """ Constructor Parameters ---------- size: int The number of maximally stored results keyf: Function, optional The memory key function. Parameters: (vars_int, vars_float), returns key Object """ self.max_size = size self.keyf = keyf if keyf is not None else get_default_keyf() self.data = {}
[docs] def clear(self): """ Clears the memory """ self.data = {}
@property def size(self): """ The number of elements currently stored in memory Returns ------- int : The number of elements currently stored in memory """ return len(self.data)
[docs] def found_individual(self, vars_int, vars_float): """ Check if entry is found in memory. Parameters ---------- vars_int: np.array The integer variable values, shape: (n_vars_int,) vars_float: np.array The float variable values, shape: (n_vars_float,) Returns ------- found: bool True if data is available """ key = self.keyf(vars_int, vars_float) return key in self.data
[docs] def found_population(self, vars_int, vars_float): """ Check if entry is found in memory. Parameters ---------- vars_int: np.array The integer variable values, shape: (n_pop, n_vars_int) vars_float: np.array The float variable values, shape: (n_pop, n_vars_float) Returns ------- found: numpy.ndarray of bool True if data is available, shape: (n_pop,) """ n_pop = len(vars_float) found = np.zeros(n_pop, dtype=bool) for pi in range(n_pop): found[pi] = self.found_individual(vars_int[pi], vars_float[pi]) return found
[docs] def store_individual(self, vars_int, vars_float, objs, cons): """ Store objs and cons data. Parameters ---------- vars_int: np.array The integer variable values, shape: (n_vars_int,) vars_float: np.array The float variable values, shape: (n_vars_float,) objs: np.array The objective function values, shape: (n_objectives,) con: np.array The constraints values, shape: (n_constraints,) """ key = self.keyf(vars_int, vars_float) if key in self.data and self.size == self.max_size: delk = next(iter(self.dict.keys())) del self.dict[delk] self.data[key] = (objs.copy(), cons.copy())
[docs] def store_population(self, vars_int, vars_float, objs, cons): """ Store objs and cons data of a population. Parameters ---------- vars_int: np.array The integer variable values, shape: (n_pop, n_vars_int) vars_float: np.array The float variable values, shape: (n_pop, n_vars_float) objs: np.array The objective function values, shape: (n_pop, n_objectives) con: np.array The constraints values, shape: (n_pop, n_constraints) """ for pi in range(len(objs)): self.store_individual(vars_int[pi], vars_float[pi], objs[pi], cons[pi])
[docs] def lookup_individual(self, vars_int, vars_float): """ Lookup results from memory. Parameters ---------- vars_int: np.array The integer variable values, shape: (n_vars_int,) vars_float: np.array The float variable values, shape: (n_vars_float,) Returns ------- results: tuple or None The results (objs, cons) if found, None otherwise """ key = self.keyf(vars_int, vars_float) if key not in self.data: return None objs, cons = self.data[key] return objs.copy(), cons.copy()
[docs] def lookup_population(self, vars_int, vars_float, target=None): """ Lookup results from memory. Parameters ---------- vars_int: np.array The integer variable values, shape: (n_pop, n_vars_int) vars_float: np.array The float variable values, shape: (n_pop, n_vars_float) target: numpy.ndarray, optional The results array to write to, shape: (n_pop, n_objs_cmpnts + n_cons_cmpnts) Returns ------- results: numpy.ndarray or None None if no results at all found, otherwise array with shape: (n_pop, n_objs_cmpnts + n_cons_cmpnts) """ results = target n_pop = len(vars_float) for pi in range(n_pop): key = self.keyf(vars_int[pi], vars_float[pi]) if key in self.data: objs, cons = self.data[key] if results is None: n_o = len(objs) n_c = len(cons) results = np.full((n_pop, n_o + n_c), np.nan, dtype=objs.dtype) results[pi] = np.r_[objs, cons] return results