age_cache_simulation/00_aoi_caching_simulation/06-multi_aoi_simulation.ipynb
Tuan-Dat Tran c74d231d69 feat(simulation): refresh and lru simulation
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2024-12-13 14:41:37 +01:00

1322 lines
179 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "71f85f2a-423f-44d2-b80d-da9ac8d3961a",
"metadata": {},
"outputs": [],
"source": [
"import simpy\n",
"import random\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import pandas as pd\n",
"from enum import Enum\n",
"import os\n",
"import shutil\n",
"from tqdm import tqdm\n",
"import math\n",
"from dataclasses import dataclass, field\n",
"from typing import List, Union, Dict\n",
"\n",
"# Constants\n",
"SEED = 42\n",
"ACCESS_COUNT_LIMIT = 10 # Total time to run the simulation\n",
"EXPERIMENT_BASE_DIR = \"./experiments/\"\n",
"TEMP_BASE_DIR = \"./.aoi_cache/\"\n",
"BASE_FILE = pd.read_csv(\"../calculated.csv\")\n",
"BASE_FILE.index += 1\n",
"\n",
"ZIPF_CONSTANT = 2 # Shape parameter for the Zipf distribution (controls skewness) Needs to be: 1< \n",
"\n",
"# Set random seeds\n",
"random.seed(SEED)\n",
"np.random.seed(SEED)\n",
"\n",
"os.makedirs(TEMP_BASE_DIR, exist_ok=True)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d88effd8-d92b-47d1-9e15-527166073e81",
"metadata": {},
"outputs": [],
"source": [
"# Types of cache\n",
"class EvictionStrategy(Enum):\n",
" LRU = 1\n",
" RANDOM_EVICTION = 2\n",
" TTL = 3"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "1d6a3c67-f9a5-4d9c-8ade-e1ca6944867c",
"metadata": {},
"outputs": [],
"source": [
"@dataclass\n",
"class DatabaseObject:\n",
" id: int\n",
" data: str\n",
" lambda_value: int\n",
" mu_value: Union[float, None]\n",
" ttl: Union[float, None]"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f40af914-a6c3-4e44-b7de-b3b40a743fb2",
"metadata": {},
"outputs": [],
"source": [
"@dataclass\n",
"class CacheObject:\n",
" id: int # id of object\n",
" data: DatabaseObject # body of object\n",
" initial_fetch_timer: float # time at which the object was initially pulled into the cache (object_start_time)\n",
" age_timer: float # time at which the object was last pulled into the cache (initial fetch)\n",
" last_access: float # time at which the object was last accesse\n",
" next_refresh: Union[float, None] # scheduled time for the object to be requested (for refresh cache)\n",
" next_expiry: Union[float, None] # scheduled time for the object to be evicted (for ttl cache) (ttl)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "00a944e4-842b-49ba-bb36-587d9c12fdf4",
"metadata": {},
"outputs": [],
"source": [
"# Base class for all cache types\n",
"@dataclass\n",
"class SimulationConfig:\n",
" db_objects: Union[int, List[DatabaseObject]]\n",
" cache_size: int\n",
" eviction_strategy: EvictionStrategy\n",
"\n",
" def __post_init__(self):\n",
" if not hasattr(self, 'eviction_strategy') or self.eviction_strategy is None:\n",
" raise ValueError(\"Eviction strategy must be defined in subclasses.\")\n",
" \n",
" def generate_objects(self):\n",
" if isinstance(self.db_objects, int):\n",
" self.db_objects = [\n",
" DatabaseObject(id=i, data=f\"Generated Object {i}\", lambda_value=np.random.zipf(ZIPF_CONSTANT), mu_value=None, ttl=None) \n",
" for i in range(self.db_objects)\n",
" ]\n",
"\n",
" def from_file(self, path: str, lambda_column_name: str):\n",
" df = pd.read_csv(path)\n",
" lambdas = df[lambda_column_name]\n",
"\n",
" self.db_objects = [\n",
" DatabaseObject(id=i, data=f\"Generated Object {i}\", lambda_value=lambdas[i], mu_value=None, ttl=None) \n",
" for i in range(self.db_objects)\n",
" ]\n",
" \n",
"# Specific cache type variants\n",
"@dataclass\n",
"class TTLSimulation(SimulationConfig):\n",
" eviction_strategy: EvictionStrategy = field(default=EvictionStrategy.TTL, init=False)\n",
" \n",
" def generate_objects(self, fixed_ttl):\n",
" if isinstance(self.db_objects, int):\n",
" self.db_objects = [\n",
" DatabaseObject(id=i, data=f\"Generated Object {i}\", lambda_value=np.random.zipf(ZIPF_CONSTANT), mu_value=None, ttl=fixed_ttl) \n",
" for i in range(self.db_objects)\n",
" ]\n",
" \n",
" def from_file(self, path: str, lambda_column_name: str, ttl_column_name: str):\n",
" df = pd.read_csv(path)\n",
" lambdas = df[lambda_column_name]\n",
" ttls = df[ttl_column_name]\n",
"\n",
" self.db_objects = [\n",
" DatabaseObject(id=i, data=f\"Generated Object {i}\", lambda_value=lambdas[i], mu_value=None, ttl=ttls[i]) \n",
" for i in range(self.db_objects)\n",
" ]\n",
" \n",
"@dataclass\n",
"class LRUSimulation(SimulationConfig):\n",
" eviction_strategy: EvictionStrategy = field(default=EvictionStrategy.LRU, init=False)\n",
"\n",
"@dataclass\n",
"class RandomEvictionSimulation(SimulationConfig):\n",
" eviction_strategy: EvictionStrategy = field(default=EvictionStrategy.RANDOM_EVICTION, init=False)\n",
"\n",
"@dataclass\n",
"class RefreshSimulation(TTLSimulation):\n",
" \n",
" def generate_objects(self, fixed_ttl, max_refresh_rate):\n",
" if isinstance(self.db_objects, int):\n",
" self.db_objects = [\n",
" DatabaseObject(id=i, data=f\"Generated Object {i}\", lambda_value=np.random.zipf(ZIPF_CONSTANT), mu_value=np.random.uniform(1, max_refresh_rate), ttl=fixed_ttl) \n",
" for i in range(self.db_objects)\n",
" ]\n",
" \n",
" def from_file(self, path: str, lambda_column_name: str, ttl_column_name: str, mu_column_name: str):\n",
" df = pd.read_csv(path)\n",
" lambdas = df[lambda_column_name]\n",
" ttls = df[ttl_column_name]\n",
" mus = df[mu_column_name]\n",
"\n",
" self.db_objects = [\n",
" DatabaseObject(id=i, data=f\"Generated Object {i}\", lambda_value=lambdas[i], mu_value=mus[i], ttl=ttls[i]) \n",
" for i in range(self.db_objects)\n",
" ]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "5cea042f-e9fc-4a1e-9750-de212ca70601",
"metadata": {},
"outputs": [],
"source": [
"class Database:\n",
" data: Dict[int, DatabaseObject]\n",
" \n",
" def __init__(self, data: List[DatabaseObject]):\n",
" self.data = {i: data[i] for i in range(len(data))}\n",
"\n",
" def get_object(self, obj_id):\n",
" # print(f\"[{env.now:.2f}] Database: Fetched {self.data.get(obj_id, 'Unknown')} for ID {obj_id}\")\n",
" return self.data.get(obj_id, None)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "499bf543-b2c6-4e4d-afcc-0a6665ce3ae1",
"metadata": {},
"outputs": [],
"source": [
"class Cache:\n",
" capacity: int\n",
" eviction_strategy: EvictionStrategy\n",
" cache_size_over_time: List[int] # To record cache state at each interval\n",
" storage: Dict[int, CacheObject]\n",
" hits: Dict[int, int] # hit counter for each object\n",
" misses: Dict[int, int] # miss counter for each object\n",
" access_count: Dict[int, int] # access counter for each object (should be hit+miss)\n",
" next_request: Dict[int, float] # scheduled time for each object to be requested\n",
" cumulative_age: Dict[int, List[float]] # list of ages of each object at the time it was requested (current time - age_timer)\n",
" cumulative_cache_time: Dict[int, List[float]] # list of total time of each object spent in cache when it was evicted (current time - initial fetch time)\n",
" request_log: Dict[int, List[float]] # list of timestamps when each object was requested\n",
" \n",
" def __init__(self, env, db, simulation_config):\n",
" self.env = env\n",
" self.db = db\n",
" self.capacity = simulation_config.cache_size\n",
" self.eviction_strategy = simulation_config.eviction_strategy\n",
" self.cache_size_over_time = []\n",
" self.storage = {}\n",
"\n",
" db_object_count = len(self.db.data)\n",
" \n",
" self.hits = {i: 0 for i in range(db_object_count)}\n",
" self.misses = {i: 0 for i in range(db_object_count)}\n",
" self.access_count = {i: 0 for i in range(db_object_count)}\n",
" self.next_request = {i: np.random.exponential(1/self.db.data[i].lambda_value) for i in range(len(self.db.data))}\n",
" self.cumulative_age = {i: [] for i in range(db_object_count)}\n",
" self.cumulative_cache_time = {i: [] for i in range(db_object_count)}\n",
" self.request_log = {i: [] for i in range(db_object_count)}\n",
"\n",
" \n",
" def get(self, obj_id):\n",
" assert len(self.storage) <= self.capacity, f\"Too many objects in cache ({len(self.storage)}).\"\n",
" # print(f\"[{self.env.now:.2f}] Requesting Object {obj_id}... (Cache Size: {len(self.storage)})\")\n",
"\n",
" # Schedule next request\n",
" next_request = self.env.now + np.random.exponential(1/self.db.data[obj_id].lambda_value)\n",
" self.request_log[obj_id].append(next_request)\n",
" self.next_request[obj_id] = next_request\n",
" self.access_count[obj_id] += 1\n",
" # print(f\"[{self.env.now:.2f}] Client: Schedule next request for {obj_id}@{next_request:.2f}\")\n",
" \n",
" if obj_id in self.storage:\n",
" # Cache hit: Refresh TTL if TTL-Cache\n",
" if self.storage[obj_id].next_expiry:\n",
" assert self.env.now <= self.storage[obj_id].next_expiry, f\"[{self.env.now:.2f}] Cache should never hit on an expired cache entry.\"\n",
" self.storage[obj_id].next_expiry = self.env.now + self.db.data[obj_id].ttl\n",
" \n",
" # Cache hit: increment hit count and update cumulative age\n",
" self.hits[obj_id] += 1\n",
" age = self.env.now - self.storage[obj_id].age_timer\n",
" self.cumulative_age[obj_id].append(age)\n",
" self.storage[obj_id].last_access = self.env.now\n",
"\n",
" assert len(self.cumulative_age[obj_id]) == self.access_count[obj_id], f\"[{self.env.now:.2f}] Age values collected and object access count do not match.\"\n",
" # print(f\"[{env.now:.2f}] {obj_id} Hit: Current Age {age:.2f} (Average: {sum(self.cumulative_age[obj_id])/len(self.cumulative_age[obj_id]):.2f}) \")\n",
" return self.storage[obj_id]\n",
" else:\n",
" # Cache miss: increment miss count\n",
" self.misses[obj_id] += 1\n",
" self.cumulative_age[obj_id].append(0)\n",
" \n",
" # Cache miss: Add TTL if TTL-Cache\n",
" # When full cache: If Non-TTL-Cache: Evict. If TTL-Cache: Don't add to Cache.\n",
" if len(self.storage) == self.capacity:\n",
" if self.eviction_strategy == EvictionStrategy.LRU:\n",
" self.evict_oldest()\n",
" elif self.eviction_strategy == EvictionStrategy.RANDOM_EVICTION:\n",
" self.evict_random()\n",
" elif self.eviction_strategy == EvictionStrategy.TTL:\n",
" # print(f\"[{self.env.now:.2f}] Cache: Capacity reached. Not accepting new request.\")\n",
" return\n",
"\n",
" # Cache miss: Construct CacheObject from Database Object\n",
" db_object = self.db.get_object(obj_id)\n",
" initial_fetch_timer=self.env.now\n",
" age_timer=self.env.now\n",
" last_access=self.env.now\n",
" next_refresh = (self.env.now + np.random.exponential(1/db_object.mu_value)) if db_object.mu_value is not None else None\n",
" next_expiry = (self.env.now + db_object.ttl) if db_object.ttl is not None else None\n",
" cache_object = CacheObject(id=obj_id, data=db_object, \n",
" initial_fetch_timer=initial_fetch_timer, age_timer=age_timer, \n",
" last_access=last_access,next_refresh=next_refresh, next_expiry=next_expiry\n",
" )\n",
" self.storage[obj_id] = cache_object\n",
" \n",
" assert len(self.cumulative_age[obj_id]) == self.access_count[obj_id], f\"[{self.env.now:.2f}] Age values collected and object access count do not match.\"rsa diagram\n",
" # print(f\"[{env.now:.2f}] {obj_id} Miss: Average Age {sum(self.cumulative_age[obj_id])/len(self.cumulative_age[obj_id]):.2f} \")\n",
" return self.storage[obj_id]\n",
"\n",
" def refresh_object(self, obj_id):\n",
" \"\"\"Refresh the object from the database to keep it up-to-date. TTL is increased on refresh.\"\"\"\n",
" assert obj_id in self.storage, f\"[{self.env.now:.2f}] Refreshed object has to be in cache\"\n",
" db_object = self.db.get_object(obj_id)\n",
" age_timer = self.env.now\n",
" next_refresh = self.env.now + np.random.exponential(1/db_object.mu_value)\n",
" # next_expiry = self.env.now + db_object.ttl if db_object.ttl is not None else None\n",
"\n",
" self.storage[obj_id].data = db_object\n",
" self.storage[obj_id].age_timer = age_timer\n",
" self.storage[obj_id].next_refresh = next_refresh\n",
"\n",
" # print(f\"[{self.env.now:.2f}] Cache: Refreshed object {obj_id}\")\n",
" \n",
" def evict_oldest(self):\n",
" \"\"\"Remove the oldest item from the cache to make space.\"\"\"\n",
" assert self.capacity == len(self.storage), f\"[{self.env.now:.2f}] Expecting cache to be at capacity\"\n",
" oldest_id = min(self.storage.items(), key=lambda item: item[1].last_access)[0]\n",
" \n",
" # print(f\"[{self.env.now:.2f}] Cache: Evicting oldest object {oldest_id}.\")\n",
" self.cumulative_cache_time[oldest_id].append(self.env.now - self.storage[oldest_id].initial_fetch_timer)\n",
" del self.storage[oldest_id]\n",
" \n",
" def evict_random(self):\n",
" \"\"\"Remove a random item from the cache to make space.\"\"\"\n",
" assert self.capacity == len(self.storage), f\"[{self.env.now:.2f}] Expecting cache to be at capacity\"\n",
" random_id = np.random.choice(list(self.storage.keys())) # Select a random key from the cache\n",
" \n",
" # print(f\"[{self.env.now:.2f}] Cache: Evicting random object {random_id}.\")\n",
" self.cumulative_cache_time[random_id].append(self.env.now - self.storage[random_id].initial_fetch_timer)\n",
" del self.storage[random_id]\n",
" \n",
" def check_expired(self, obj_id):\n",
" \"\"\"Remove object if its TTL expired.\"\"\"\n",
" assert self.storage, f\"[{self.env.now:.2f}] Expecting cache to be not empty\"\n",
" assert self.env.now >= self.storage[obj_id].next_expiry\n",
" \n",
" # print(f\"[{self.env.now:.2f}] Cache: Object {obj_id} expired\")\n",
" self.cumulative_cache_time[obj_id].append(self.env.now - self.storage[obj_id].initial_fetch_timer)\n",
" del self.storage[obj_id]\n",
"\n",
" \n",
" def record_cache_state(self):\n",
" \"\"\"Record the current cache state (number of objects in cache) over time.\"\"\"\n",
" self.cache_size_over_time.append((self.env.now, len(self.storage)))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "687f5634-8edf-4337-b42f-bbb292d47f0f",
"metadata": {},
"outputs": [],
"source": [
"def client_request_process(env, cache, event):\n",
" \"\"\"Client process that makes requests for objects from the cache.\"\"\"\n",
" last_print = 0\n",
" with tqdm(total=ACCESS_COUNT_LIMIT, desc=\"Progress\", leave=True) as pbar:\n",
" while True:\n",
" request_id, next_request = min(cache.next_request.items(), key=lambda x: x[1])\n",
" expiry_id = -1\n",
" next_expiry = float('inf')\n",
" refresh_id = -1\n",
" next_refresh = float('inf')\n",
"\n",
" if cache.storage:\n",
" expiry_id, next_expiry = min(cache.storage.items(), key=lambda x: x[1].next_expiry if x[1].next_expiry is not None else float('inf'))\n",
" next_expiry = cache.storage[expiry_id].next_expiry\n",
" refresh_id, next_refresh = min(cache.storage.items(), key=lambda x: x[1].next_refresh if x[1].next_refresh is not None else float('inf'))\n",
" next_refresh = cache.storage[refresh_id].next_refresh\n",
"\n",
" events = [\n",
" (request_id, next_request),\n",
" (expiry_id, next_expiry),\n",
" (refresh_id, next_refresh)\n",
" ]\n",
"\n",
" event_id, event_timestamp = min(events, key=lambda x: x[1] if x[1] is not None else float('inf'))\n",
" \n",
" # if event_id == request_id and event_timestamp == next_request:\n",
" # print(f\"[{env.now:.2f}] Waiting for request...\")\n",
" # elif event_id == expiry_id and event_timestamp == next_expiry:\n",
" # print(f\"[{env.now:.2f}] Waiting for expiry until...\")\n",
" # elif event_id == refresh_id and event_timestamp == next_refresh:\n",
" # print(f\"[{env.now:.2f}] Waiting for refresh...\")\n",
" \n",
" yield(env.timeout(event_timestamp - env.now))\n",
"\n",
" if event_id == request_id and event_timestamp == next_request:\n",
" assert env.now >= next_request, f\"[{env.now}] Time for request should've been reached for Object {request_id}\"\n",
" cache.get(request_id)\n",
" elif event_id == expiry_id and event_timestamp == next_expiry:\n",
" assert env.now >= next_expiry, f\"[{env.now}] Time for expiry should've been reached for Object {expiry_id}\"\n",
" cache.check_expired(expiry_id)\n",
" elif event_id == refresh_id and event_timestamp == next_refresh:\n",
" assert env.now >= next_refresh, f\"[{env.now}] Time for refresh should've been reached for Object {refresh_id}\"\n",
" cache.refresh_object(refresh_id)\n",
" else:\n",
" assert False, \"Unreachable\"\n",
"\n",
" # For progress bar\n",
" if (int(env.now) % 1) == 0 and int(env.now) != last_print:\n",
" last_print = int(env.now)\n",
" pbar.n = min(cache.access_count.values())\n",
" pbar.refresh()\n",
" \n",
" # Simulation stop condition\n",
" if all(access_count >= ACCESS_COUNT_LIMIT for access_count in cache.access_count.values()):\n",
" print(f\"Simulation ended after {env.now} seconds.\")\n",
" for obj_id in cache.storage.keys():\n",
" cache.cumulative_cache_time[obj_id].append(env.now - cache.storage[obj_id].initial_fetch_timer)\n",
" event.succeed()\n",
" \n",
" cache.record_cache_state()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "c8516830-9880-4d9e-a91b-000338baf9d6",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"class Simulation:\n",
" def __init__(self, simulation_config: Union[TTLSimulation, LRUSimulation, RandomEvictionSimulation, RefreshSimulation]):\n",
" # Initialize simulation environment\n",
" self.env = simpy.Environment()\n",
" \n",
" # Instantiate components\n",
" self.db = Database(simulation_config.db_objects)\n",
" self.cache = Cache(self.env, self.db, simulation_config)\n",
"\n",
" def run_simulation(self):\n",
" # Start processes\n",
" # env.process(age_cache_process(env, cache))\n",
" stop_event = self.env.event()\n",
" self.env.process(client_request_process(self.env, self.cache, stop_event))\n",
" \n",
" # Run the simulation\n",
" self.env.run(until=stop_event)\n",
" self.end_time = self.env.now"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "e269b607-16b9-46d0-8a97-7324f2002c72",
"metadata": {},
"outputs": [],
"source": [
"# Simulate with a Cache that does random evictions, We'll have 100 Database Objects and a Cache Size of 10\n",
"# We'll generate lambdas from a zipf distribution\n",
"# config = RandomEvictionSimulation(100, 10)\n",
"# config.generate_objects()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "33fdc5fd-1f39-4b51-b2c7-6ea6acf2b753",
"metadata": {},
"outputs": [],
"source": [
"# Simulate with a Cache that does lru, We'll have 100 Database Objects and a Cache Size of 10\n",
"# We'll generate lambdas from a zipf distribution\n",
"# config = LRUSimulation(100, 10)\n",
"# config.from_file('./input/2024-12-13/input.csv', 'Lambda')"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "6c391bfd-b294-4ff7-8b22-51777368a6b9",
"metadata": {},
"outputs": [],
"source": [
"# Simulate with a Cache that does Refreshes with TTL based eviction, We'll have 100 Database Objects and a Cache Size of 10\n",
"# We'll generate lambdas from a zipf distribution. Each object will have a fixed ttl of 1 when its pulled into the cache. Mu for the refresh rate is 10\n",
"config = RefreshSimulation(100, 10)\n",
"config.from_file(path='./input/2024-12-13/output.csv', lambda_column_name='Lambda', ttl_column_name='TTL_2', mu_column_name='u_opt_2')"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "0a444c9d-53dd-4cab-b8f1-100ad3ab213a",
"metadata": {},
"outputs": [],
"source": [
"# Simulate with a Cache that does TTL based eviction, We'll have 100 Database Objects and a Cache Size of 10\n",
"# We'll take lambdas from the \"lambda\" column of the file \"../calculated.csv\" and the TTLs for each object from the \"optimal_TTL\" column of the same file.\n",
"# config = TTLSimulation(100, 10)\n",
"# config.from_file(\"../calculated.csv\", \"lambda\", \"optimal_TTL\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "66f65699-a3c9-48c4-8f1f-b9d7834c026a",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Progress: 90%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▌ | 9/10 [00:01<00:00, 6.32it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Simulation ended after 682.3621311693207 seconds.\n",
"CPU times: user 1.34 s, sys: 244 ms, total: 1.59 s\n",
"Wall time: 1.44 s\n"
]
}
],
"source": [
"%%time\n",
"\n",
"simulation = Simulation(config)\n",
"simulation.run_simulation()"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "6f900c68-1f34-48d1-b346-ef6ea6911fa5",
"metadata": {},
"outputs": [],
"source": [
"cache = simulation.cache\n",
"db = simulation.db\n",
"simulation_end_time = simulation.end_time\n",
"database_object_count = len(db.data)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "f9f46f00-26f8-48c5-8daa-4bf5408c2595",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf]"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[o.next_expiry for o in cache.storage.values()]"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "3b6f7c1f-ea54-4496-bb9a-370cee2d2751",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Object 0: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 1: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 2: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 3: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 4: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 5: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 6: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 7: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 8: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 9: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 10: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 11: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 12: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 13: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 14: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 15: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 16: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 17: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 18: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 19: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 20: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 21: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 22: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 23: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 24: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 25: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 26: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 27: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 28: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 29: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 30: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 31: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 32: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 33: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 34: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 35: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 36: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 37: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 38: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 39: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 40: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 41: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 42: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 43: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 44: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 45: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 46: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 47: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 48: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 49: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 50: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 51: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 52: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 53: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 54: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 55: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 56: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 57: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 58: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 59: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 60: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 61: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 62: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 63: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 64: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 65: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 66: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 67: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 68: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 69: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 70: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 71: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 72: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 73: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 74: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 75: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 76: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 77: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 78: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 79: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 80: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 81: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 82: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 83: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 84: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 85: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 86: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 87: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 88: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 89: Hit Rate = 0.00, Expected Hit Rate = 0.00, Average Time spend in Cache: 0.00, Average Age = 0.00, Expected Age = 0.00\n",
"Object 90: Hit Rate = 0.99, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 0.53, Expected Age = 376.97\n",
"Object 91: Hit Rate = 0.99, Expected Hit Rate = 1.00, Average Time spend in Cache: 0.99, Average Age = 0.50, Expected Age = 352.37\n",
"Object 92: Hit Rate = 0.99, Expected Hit Rate = 1.00, Average Time spend in Cache: 0.99, Average Age = 0.50, Expected Age = 312.66\n",
"Object 93: Hit Rate = 0.99, Expected Hit Rate = 1.00, Average Time spend in Cache: 0.99, Average Age = 0.51, Expected Age = 319.02\n",
"Object 94: Hit Rate = 0.99, Expected Hit Rate = 1.00, Average Time spend in Cache: 0.99, Average Age = 0.49, Expected Age = 378.40\n",
"Object 95: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 0.40, Expected Age = 368.79\n",
"Object 96: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 0.36, Expected Age = 332.67\n",
"Object 97: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 0.33, Expected Age = 345.01\n",
"Object 98: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 0.28, Expected Age = 367.84\n",
"Object 99: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 0.23, Expected Age = 349.75\n"
]
}
],
"source": [
"statistics = []\n",
"# Calculate and print hit rate and average age for each object\n",
"for obj_id in range(database_object_count):\n",
" if cache.access_count[obj_id] != 0:\n",
" hit_rate = cache.hits[obj_id] / max(1, cache.access_count[obj_id])\n",
" expected_hit_rate = 1-math.exp(-db.data[obj_id].lambda_value*(db.data[obj_id].ttl if db.data[obj_id].ttl is not None else 1))\n",
" avg_cache_time = sum(cache.cumulative_cache_time[obj_id]) / max(1, simulation_end_time) \n",
" avg_age = sum(cache.cumulative_age[obj_id]) / max(len(cache.cumulative_age[obj_id]), 1)\n",
" expected_age = hit_rate / (db.data[obj_id].lambda_value * (1 - pow(hit_rate,2)))\n",
" print(f\"Object {obj_id}: Hit Rate = {hit_rate:.2f}, Expected Hit Rate = {expected_hit_rate:.2f}, Average Time spend in Cache: {avg_cache_time:.2f}, Average Age = {avg_age:.2f}, Expected Age = {expected_age:.2f}\")\n",
" statistics.append({\"obj_id\": obj_id,\"hit_rate\": hit_rate, \"expected_hit_rate\": expected_hit_rate, \"avg_cache_time\":avg_cache_time, \"avg_age\": avg_age, \"expected_age\": expected_age})"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "b2d18372-cdba-4151-ae32-5bf45466bf94",
"metadata": {},
"outputs": [],
"source": [
"stats = pd.DataFrame(statistics)\n",
"stats.to_csv(f\"{TEMP_BASE_DIR}/hit_age.csv\",index=False)\n",
"stats.drop(\"obj_id\", axis=1).describe().to_csv(f\"{TEMP_BASE_DIR}/overall_hit_age.csv\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "80971714-44f1-47db-9e89-85be7c885bde",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_16109/3693436280.py:26: RuntimeWarning: invalid value encountered in divide\n",
" age_delta_p = pd.DataFrame(np.where(expected_age.to_numpy().T[0] != 0, age_delta.to_numpy().T[0] / expected_age.to_numpy().T[0], 0), columns=['age_delta in %'])\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>access_count</th>\n",
" <th>hits</th>\n",
" <th>misses</th>\n",
" <th>mu</th>\n",
" <th>lambda</th>\n",
" <th>hit_rate</th>\n",
" <th>optimal_hitrates</th>\n",
" <th>expected_hit_rate</th>\n",
" <th>expected_hit_rate_delta</th>\n",
" <th>avg_cache_time</th>\n",
" <th>cache_time_delta</th>\n",
" <th>avg_age</th>\n",
" <th>expected_age</th>\n",
" <th>age_delta</th>\n",
" <th>age_delta in %</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>22</td>\n",
" <td>0</td>\n",
" <td>22</td>\n",
" <td>1.000000</td>\n",
" <td>0.0251</td>\n",
" <td>0.000000</td>\n",
" <td>0.0513</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>13</td>\n",
" <td>0</td>\n",
" <td>13</td>\n",
" <td>1.000000</td>\n",
" <td>0.0253</td>\n",
" <td>0.000000</td>\n",
" <td>0.0513</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>22</td>\n",
" <td>0</td>\n",
" <td>22</td>\n",
" <td>1.000000</td>\n",
" <td>0.0255</td>\n",
" <td>0.000000</td>\n",
" <td>0.4000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>20</td>\n",
" <td>0</td>\n",
" <td>20</td>\n",
" <td>1.000000</td>\n",
" <td>0.0257</td>\n",
" <td>0.000000</td>\n",
" <td>0.2254</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>23</td>\n",
" <td>0</td>\n",
" <td>23</td>\n",
" <td>1.000000</td>\n",
" <td>0.0260</td>\n",
" <td>0.000000</td>\n",
" <td>0.0000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>95</th>\n",
" <td>204</td>\n",
" <td>203</td>\n",
" <td>1</td>\n",
" <td>2.344666</td>\n",
" <td>0.2759</td>\n",
" <td>0.995098</td>\n",
" <td>0.0000</td>\n",
" <td>1.0</td>\n",
" <td>-0.004902</td>\n",
" <td>0.996384</td>\n",
" <td>-0.001286</td>\n",
" <td>0.396097</td>\n",
" <td>368.790815</td>\n",
" <td>-368.394718</td>\n",
" <td>-0.998926</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96</th>\n",
" <td>220</td>\n",
" <td>219</td>\n",
" <td>1</td>\n",
" <td>2.563445</td>\n",
" <td>0.3299</td>\n",
" <td>0.995455</td>\n",
" <td>0.0000</td>\n",
" <td>1.0</td>\n",
" <td>-0.004545</td>\n",
" <td>0.996714</td>\n",
" <td>-0.001260</td>\n",
" <td>0.361816</td>\n",
" <td>332.674842</td>\n",
" <td>-332.313026</td>\n",
" <td>-0.998912</td>\n",
" </tr>\n",
" <tr>\n",
" <th>97</th>\n",
" <td>287</td>\n",
" <td>286</td>\n",
" <td>1</td>\n",
" <td>2.876043</td>\n",
" <td>0.4152</td>\n",
" <td>0.996516</td>\n",
" <td>0.0000</td>\n",
" <td>1.0</td>\n",
" <td>-0.003484</td>\n",
" <td>0.998031</td>\n",
" <td>-0.001515</td>\n",
" <td>0.334248</td>\n",
" <td>345.013400</td>\n",
" <td>-344.679152</td>\n",
" <td>-0.999031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>98</th>\n",
" <td>423</td>\n",
" <td>422</td>\n",
" <td>1</td>\n",
" <td>3.381806</td>\n",
" <td>0.5743</td>\n",
" <td>0.997636</td>\n",
" <td>0.5528</td>\n",
" <td>1.0</td>\n",
" <td>-0.002364</td>\n",
" <td>0.999934</td>\n",
" <td>-0.002298</td>\n",
" <td>0.283229</td>\n",
" <td>367.838593</td>\n",
" <td>-367.555365</td>\n",
" <td>-0.999230</td>\n",
" </tr>\n",
" <tr>\n",
" <th>99</th>\n",
" <td>700</td>\n",
" <td>699</td>\n",
" <td>1</td>\n",
" <td>4.462294</td>\n",
" <td>1.0000</td>\n",
" <td>0.998571</td>\n",
" <td>0.0000</td>\n",
" <td>1.0</td>\n",
" <td>-0.001429</td>\n",
" <td>0.999833</td>\n",
" <td>-0.001261</td>\n",
" <td>0.227276</td>\n",
" <td>349.749821</td>\n",
" <td>-349.522545</td>\n",
" <td>-0.999350</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>100 rows × 15 columns</p>\n",
"</div>"
],
"text/plain": [
" access_count hits misses mu lambda hit_rate optimal_hitrates \\\n",
"0 22 0 22 1.000000 0.0251 0.000000 0.0513 \n",
"1 13 0 13 1.000000 0.0253 0.000000 0.0513 \n",
"2 22 0 22 1.000000 0.0255 0.000000 0.4000 \n",
"3 20 0 20 1.000000 0.0257 0.000000 0.2254 \n",
"4 23 0 23 1.000000 0.0260 0.000000 0.0000 \n",
".. ... ... ... ... ... ... ... \n",
"95 204 203 1 2.344666 0.2759 0.995098 0.0000 \n",
"96 220 219 1 2.563445 0.3299 0.995455 0.0000 \n",
"97 287 286 1 2.876043 0.4152 0.996516 0.0000 \n",
"98 423 422 1 3.381806 0.5743 0.997636 0.5528 \n",
"99 700 699 1 4.462294 1.0000 0.998571 0.0000 \n",
"\n",
" expected_hit_rate expected_hit_rate_delta avg_cache_time \\\n",
"0 0.0 0.000000 0.000000 \n",
"1 0.0 0.000000 0.000000 \n",
"2 0.0 0.000000 0.000000 \n",
"3 0.0 0.000000 0.000000 \n",
"4 0.0 0.000000 0.000000 \n",
".. ... ... ... \n",
"95 1.0 -0.004902 0.996384 \n",
"96 1.0 -0.004545 0.996714 \n",
"97 1.0 -0.003484 0.998031 \n",
"98 1.0 -0.002364 0.999934 \n",
"99 1.0 -0.001429 0.999833 \n",
"\n",
" cache_time_delta avg_age expected_age age_delta age_delta in % \n",
"0 0.000000 0.000000 0.000000 0.000000 0.000000 \n",
"1 0.000000 0.000000 0.000000 0.000000 0.000000 \n",
"2 0.000000 0.000000 0.000000 0.000000 0.000000 \n",
"3 0.000000 0.000000 0.000000 0.000000 0.000000 \n",
"4 0.000000 0.000000 0.000000 0.000000 0.000000 \n",
".. ... ... ... ... ... \n",
"95 -0.001286 0.396097 368.790815 -368.394718 -0.998926 \n",
"96 -0.001260 0.361816 332.674842 -332.313026 -0.998912 \n",
"97 -0.001515 0.334248 345.013400 -344.679152 -0.999031 \n",
"98 -0.002298 0.283229 367.838593 -367.555365 -0.999230 \n",
"99 -0.001261 0.227276 349.749821 -349.522545 -0.999350 \n",
"\n",
"[100 rows x 15 columns]"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"access_count = pd.DataFrame.from_dict(cache.access_count, orient='index', columns=['access_count'])\n",
"hits = pd.DataFrame.from_dict(cache.hits, orient='index', columns=['hits'])\n",
"misses = pd.DataFrame.from_dict(cache.misses, orient='index', columns=['misses'])\n",
"mu = pd.DataFrame.from_dict({l: db.data[l].mu_value for l in range(database_object_count)}, orient='index', columns=['mu'])\n",
"lmbda = pd.DataFrame.from_dict({l: db.data[l].lambda_value for l in range(database_object_count)}, orient='index', columns=['lambda'])\n",
"\n",
"hit_rate = pd.DataFrame(stats['hit_rate'])\n",
"hit_rate.index = range(database_object_count)\n",
"optimal_hitrate = pd.DataFrame(BASE_FILE['optimal_hitrates'])\n",
"optimal_hitrate.index = range(database_object_count)\n",
"expected_hit_rate = pd.DataFrame(stats['expected_hit_rate'])\n",
"expected_hit_rate.index = range(database_object_count)\n",
"expected_hit_rate_delta = pd.DataFrame((hit_rate.to_numpy()-expected_hit_rate.to_numpy()), columns=['expected_hit_rate_delta'])\n",
"expected_hit_rate_delta.index = range(database_object_count)\n",
"avg_cache_time = pd.DataFrame(stats['avg_cache_time'])\n",
"avg_cache_time.index = range(database_object_count)\n",
"cache_time_delta = pd.DataFrame((hit_rate.to_numpy()-avg_cache_time.to_numpy()), columns=['cache_time_delta'])\n",
"cache_time_delta.index = range(database_object_count)\n",
"\n",
"avg_age = pd.DataFrame(stats['avg_age'])\n",
"avg_age.index = range(database_object_count)\n",
"expected_age = pd.DataFrame(stats['expected_age'])\n",
"expected_age.index = range(database_object_count)\n",
"age_delta = pd.DataFrame((avg_age.to_numpy()-expected_age.to_numpy()), columns=['age_delta'])\n",
"age_delta.index = range(database_object_count)\n",
"age_delta_p = pd.DataFrame(np.where(expected_age.to_numpy().T[0] != 0, age_delta.to_numpy().T[0] / expected_age.to_numpy().T[0], 0), columns=['age_delta in %'])\n",
"age_delta_p.index = range(database_object_count)\n",
"\n",
"merged = access_count.merge(hits, left_index=True, right_index=True).merge(misses, left_index=True, right_index=True) \\\n",
" .merge(mu, left_index=True, right_index=True).merge(lmbda, left_index=True, right_index=True) \\\n",
" .merge(hit_rate, left_index=True, right_index=True).merge(optimal_hitrate, left_index=True, right_index=True).merge(expected_hit_rate, left_index=True, right_index=True).merge(expected_hit_rate_delta, left_index=True, right_index=True) \\\n",
" .merge(avg_cache_time, left_index=True, right_index=True).merge(cache_time_delta, left_index=True, right_index=True) \\\n",
" .merge(avg_age, left_index=True, right_index=True).merge(expected_age, left_index=True, right_index=True).merge(age_delta, left_index=True, right_index=True).merge(age_delta_p, left_index=True, right_index=True)\n",
"merged.to_csv(f\"{TEMP_BASE_DIR}/details.csv\", index_label=\"obj_id\")\n",
"merged"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "01f8f9ee-c278-4a22-8562-ba02e77f5ddd",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAACVcAAAHWCAYAAAB5HisgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABobklEQVR4nOzdeZjd4/0//ueZ7PuCbEQEsSSEotS+RqjaqiVKEWuJSmjVVksstbQ0+NhSraWlam8pItbULtTWWhJiKSW1RCQhmWTO7w+/zNeYE2ZikpOcPB7XNdc1537f7/d5vc8588qQZ+67UCwWiwEAAAAAAAAAAKCOqnIXAAAAAAAAAAAAsCgSrgIAAAAAAAAAAChBuAoAAAAAAAAAAKAE4SoAAAAAAAAAAIAShKsAAAAAAAAAAABKEK4CAAAAAAAAAAAoQbgKAAAAAAAAAACgBOEqAAAAAAAAAACAEoSrAAAAAAAAAAAAShCuAgAAAEjywAMPpFAo5MYbbyx3KQ3y3nvv5Qc/+EGWWmqpFAqFjBo1qsmu/frrr6dQKOQ3v/nN18495ZRTUigUmuy5F4ZCoZBTTjml3GU0iUKhkMMPP7zcZSzWVlhhhey3337lLgMAAABYRAlXAQAAAAvNlVdemUKhkNatW+ftt9+ud3yLLbbIGmusUYbKFj9HHnlkxowZk+OOOy5//OMfs912233l/OnTp+e0007LwIED07Zt23Tq1Cmbbrpprr766hSLxYVUdePdcccdi00Q6oEHHsj3v//99OjRIy1btky3bt2y44475uabby53aU2iuro6F1xwQb797W+nQ4cOad++fb797W/nggsuSHV1dbnLqzU3KNmQLwAAAICv07zcBQAAAABLnpkzZ+ass87KhRdeWO5SFlv33Xdfdt555/z85z//2rnvvfdett5667z44osZMmRIDj/88Hz22We56aabsu++++aOO+7INddck2bNmjW6jl/+8pc59thj5+cWGuSOO+7IRRdd1KQBq08//TTNmzft/xY7+eSTc+qpp6Zfv3455JBD0qdPn3zwwQe54447sttuu+Waa67Jj370oyZ9zoVp+vTp2WGHHfLggw/me9/7Xvbbb79UVVXlrrvuyvDhw3PzzTfn73//e9q1a1fuUrP66qvnj3/8Y52x4447Lu3bt88JJ5xQb/7LL7+cqir/BhUAAAAoTbgKAAAAWOjWXnvt/O53v8txxx2XXr16lbuchWr69OlNEkCZPHlyOnfu3KC5++67b1588cXccsst2WmnnWrHjzjiiBx99NH5zW9+k29961s55phjGl1H8+bNmzyotKC1bt26Sa9344035tRTT80PfvCDXHvttWnRokXtsaOPPjpjxoxZpFZ2mh9HHXVUHnzwwVx44YV1tiE89NBDc9FFF+Xwww/Pz3/+81xyySULraZisZjPPvssbdq0qTPevXv37L333nXGzjrrrCy99NL1xpOkVatWC7ROAAAAYPHmn2QBAAAAC93xxx+fOXPm5KyzzvrKea+//noKhUKuvPLKescKhUKd1YxOOeWUFAqFvPLKK9l7773TqVOnLLPMMjnxxBNTLBbz1ltvZeedd07Hjh3To0ePnHvuuSWfc86cOTn++OPTo0ePtGvXLjvttFPeeuutevMef/zxbLfddunUqVPatm2bzTffPA8//HCdOXNr+ve//50f/ehH6dKlSzbZZJOvvOfXXnstP/zhD9O1a9e0bds23/nOd/L3v/+99vjcrRWLxWIuuuiir93e7LHHHsuYMWOy33771QlWzXXmmWemX79+Ofvss/Ppp5/WO/7b3/42ffr0SZs2bbL55pvnhRdeKHmPX/anP/0p6667btq0aZOuXbtmyJAh83wdv/vd76ZLly5p165dBg4cmPPPPz9Jst9+++Wiiy5KkpJbuV133XVZd91106FDh3Ts2DFrrrlm7blfZV6fnYkTJ2a//fZL586d06lTpwwdOjQzZsz42uudeOKJ6dq1a/7whz/UCVbNNXjw4Hzve99LksyaNSsnnXRS1l133XTq1Cnt2rXLpptumvvvv7/eeTU1NTn//POz5pprpnXr1llmmWWy3XbbZfz48fXm3nrrrVljjTXSqlWrDBgwIHfddVe9OW+//Xb233//dO/evXbeH/7wh6+9v//85z/5/e9/n6222qpOsGquYcOGZcstt8zll1+e//znP0mSNdZYI1tuuWXJe1p22WXzgx/8oM7YqFGjMmDAgLRu3Trdu3fPIYccko8++qjOuSussEK+973vZcyYMVlvvfXSpk2bXHbZZV9b/9dZYYUVst9++9U+nvsz9tBDD+WII47IMsssk86dO+eQQw7JrFmzMmXKlOyzzz7p0qVLunTpkl/84hf1ttZs6D0BAAAAiz7hKgAAAGCh69u3b/bZZ5/87ne/yzvvvNOk195jjz1SU1OTs846KxtssEFOP/30jBo1KoMGDcqyyy6bs88+OyuvvHJ+/vOfZ9y4cfXOP+OMM/L3v/89xxxzTI444oiMHTs222yzTZ3g0X333ZfNNtssU6dOzcknn5xf/epXmTJlSrbaaqs88cQT9a75wx/+MDNmzMivfvWrHHTQQfOs/b333stGG22UMWPG5LDDDssZZ5yRzz77LDvttFNuueWWJMlmm21Wu+XZoEGD8sc//rHeFmhfdNtttyVJ9tlnn5LHmzdvnh/96Ef56KOP6oXDrr766lxwwQUZNmxYjjvuuLzwwgvZaqut8t57783z+ZLPX8N99tkn/fr1y3nnnZcRI0bk3nvvzWabbZYpU6bUzhs7dmw222yz/Pvf/87w4cNz7rnnZsstt8ztt9+eJDnkkEMyaNCgJKm9z7n3Onbs2Oy5557p0qVLzj777Jx11lnZYost6t1DY+y+++755JNPcuaZZ2b33XfPlVdemZEjR37lORMmTMhLL72UXXbZJR06dPja55g6dWouv/zybLHFFjn77LNzyimn5H//+18GDx6cZ555ps7cAw44ICNGjEjv3r1z9tln59hjj03r1q3z2GOP1Zn30EMP5bDDDsuQIUNyzjnn5LPPPstuu+2WDz74oHbOe++9l+985zu55557cvjhh+f888/PyiuvnAMOOCCjRo36yprvvPPOzJkzZ56foeTzz9fs2bNrQ1177LFHxo0bl3fffbdere+8806GDBlSO3bIIYfk6KOPzsYbb5zzzz8/Q4cOzTXXXJPBgwfXW/Hr5Zdfzp577plBgwbl/PPPz9prr/2VtX8TP/3pTzNhwoSMHDkyO+20U0aPHp0TTzwxO+64Y+bMmZNf/epX2WSTTfLrX/+63s9gY+4JAAAAWMQVAQAAABaSK664opik+OSTTxZfffXVYvPmzYtHHHFE7fHNN9+8OGDAgNrHkyZNKiYpXnHFFfWulaR48skn1z4++eSTi0mKBx98cO3Y7Nmzi8stt1yxUCgUzzrrrNrxjz76qNimTZvivvvuWzt2//33F5MUl1122eLUqVNrx6+//vpikuL5559fLBaLxZqammK/fv2KgwcPLtbU1NTOmzFjRrFv377FQYMG1atpzz33bNDrM2LEiGKS4j/+8Y/asU8++aTYt2/f4gorrFCcM2dOnfsfNmzY115zl112KSYpfvTRR/Occ/PNNxeTFC+44IJisfj/Xvc2bdoU//Of/9TOe/zxx4tJikceeWS9e5zr9ddfLzZr1qx4xhln1HmO559/vti8efPa8dmzZxf79u1b7NOnT73avvi6Dhs2rFjqf2ENHz682LFjx+Ls2bO/9jX4snl9dvbff/8683bdddfiUkst9ZXX+utf/1pMUvztb3/boOeePXt2cebMmXXGPvroo2L37t3rPP99991XTFLn52OuL74+SYotW7YsTpw4sXbs2WefLSYpXnjhhbVjBxxwQLFnz57F999/v861hgwZUuzUqVNxxowZ86x57ufyn//85zznPP3008UkxaOOOqpYLBaLL7/8cr0aisVi8bDDDiu2b9++9vn+8Y9/FJMUr7nmmjrz7rrrrnrjffr0KSYp3nXXXfOsY14GDBhQ3HzzzUse69OnT51eMLdPfflnfMMNNywWCoXiT37yk9qxuT3mi9duzD0BAAAAiz4rVwEAAABlseKKK+bHP/5xRo8enf/+979Ndt0DDzyw9vtmzZplvfXWS7FYzAEHHFA73rlz56y66qp57bXX6p2/zz771FmB6Ac/+EF69uyZO+64I0nyzDPPZMKECfnRj36UDz74IO+//37ef//9TJ8+PVtvvXXGjRuXmpqaOtf8yU9+0qDa77jjjqy//vp1tg5s3759Dj744Lz++uv597//3bAX4Qs++eSTJPnKVZXmHps6dWqd8V122SXLLrts7eP1118/G2ywQe1rUcrNN9+cmpqa7L777rWvzfvvv58ePXqkX79+tdvf/fOf/8ykSZMyYsSIdO7cuc41vmqbw7k6d+6c6dOnZ+zYsV87t6G+/D5tuumm+eCDD+q9Ll8091hDVq1KPv9MtmzZMsnnW8d9+OGHmT17dtZbb708/fTTtfNuuummFAqFnHzyyfWu8eXXZ5tttslKK61U+3jgwIHp2LFj7ee7WCzmpptuyo477phisVjnfRk8eHA+/vjjOs/9ZfPzGVpllVWy9tpr5y9/+UvtnDlz5uTGG2/MjjvumDZt2iRJbrjhhnTq1CmDBg2qU9e6666b9u3b19susW/fvhk8ePA862hKBxxwQJ3XeoMNNqjXS+b2mC/2ksbeEwAAALBoa17uAgAAAIAl1y9/+cv88Y9/zFlnnZXzzz+/Sa65/PLL13ncqVOntG7dOksvvXS98S9umzZXv3796jwuFApZeeWV8/rrryf5fBu4JNl3333nWcPHH3+cLl261D7u27dvg2p/4403ssEGG9QbX3311WuPr7HGGg261lxzQy+ffPJJvRDTXPMKz3z5tUg+D81cf/3183y+CRMmpFgsljw3SVq0aJEkefXVV5Ok0fcz12GHHZbrr78+22+/fZZddtlsu+222X333bPddtvN1/WS+p+due/hRx99lI4dO5Y8Z+743NewIa666qqce+65eemll+psEffFz8mrr76aXr16pWvXro2ue27tH330UZLkf//7X6ZMmZLRo0dn9OjRJa8xefLkeV7/i5+heSn1Gdpjjz1y/PHH5+23386yyy6bBx54IJMnT84ee+xRO2fChAn5+OOP061btwbV1dCfpaZQqpckSe/eveuNz32tk8bfEwAAALBoE64CAAAAymbFFVfM3nvvndGjR+fYY4+td3xeKxjNmTNnntds1qxZg8aSz1f0aay5q1L9+te/ztprr11yTvv27es8nrtKTzmsvvrqufXWW/Pcc89ls802KznnueeeS5L079//Gz9fTU1NCoVC7rzzzpKv+5dfm/nVrVu3PPPMMxkzZkzuvPPO3Hnnnbniiiuyzz775Kqrrpqva87P52S11VZLkjz//PMNeo4//elP2W+//bLLLrvk6KOPTrdu3dKsWbOceeaZtYGzxvq6uud+Zvfee+95hgIHDhw4z+vPDfc999xz8/zMl/oM7bHHHjnuuONyww03ZMSIEbn++uvTqVOnOgG4mpqadOvWLddcc03J6y6zzDJ1Hi/Mn6V5va6lxr/4GWnsPQEAAACLNuEqAAAAoKx++ctf5k9/+lPOPvvsesfmrhw0ZcqUOuNvvPHGAqtn7spUcxWLxUycOLE2fDJ3+7WOHTtmm222adLn7tOnT15++eV64y+99FLt8cb63ve+lzPPPDNXX311yXDVnDlzcu2116ZLly7ZeOON6xz78muRJK+88kpWWGGFeT7fSiutlGKxmL59+2aVVVb5ynlJ8sILL3zl6/hVWwS2bNkyO+64Y3bcccfU1NTksMMOy2WXXZYTTzwxK6+88jzPa0qrrLJKVl111fz1r3/N+eef/7XhsRtvvDErrrhibr755jr39uXt/1ZaaaWMGTMmH374YYNWr/oqyyyzTDp06JA5c+bM12d2++23T7NmzfLHP/4x++yzT8k5V199dZo3b14nONW3b9+sv/76+ctf/pLDDz88N998c3bZZZe0atWqds5KK62Ue+65JxtvvHFZQ4hNqRLvCQAAAJZkVeUuAAAAAFiyrbTSStl7771z2WWX5d13361zrGPHjll66aUzbty4OuMXX3zxAqvn6quvrrP92Y033pj//ve/2X777ZMk6667blZaaaX85je/ybRp0+qd/7///W++n/u73/1unnjiiTz66KO1Y9OnT8/o0aOzwgorzNfKUhtttFG22WabXHHFFbn99tvrHT/hhBPyyiuv5Be/+EW9IMitt96at99+u/bxE088kccff7z2tSjl+9//fpo1a5aRI0fWW/GpWCzWbsW4zjrrpG/fvhk1alS98NwXz2vXrl2S+gG7L2/pWFVVVRuAmzlz5jzrWxBGjhyZDz74IAceeGBmz55d7/jdd99d+9rPXfXoi/f4+OOP13nPk2S33XZLsVjMyJEj612vsSuuNWvWLLvttltuuummvPDCC/WOf91ntnfv3hk6dGjuueeeXHLJJfWOX3rppbnvvvtywAEHZLnllqtzbI899shjjz2WP/zhD3n//ffrbAmYJLvvvnvmzJmT0047rd51Z8+eXe99XxxU4j0BAADAkszKVQAAAEDZnXDCCfnjH/+Yl19+OQMGDKhz7MADD8xZZ52VAw88MOutt17GjRuXV155ZYHV0rVr12yyySYZOnRo3nvvvYwaNSorr7xyDjrooCSfh3guv/zybL/99hkwYECGDh2aZZddNm+//Xbuv//+dOzYMbfddtt8Pfexxx6bP//5z9l+++1zxBFHpGvXrrnqqqsyadKk3HTTTamqmr9/J3f11Vdn6623zs4775wf/ehH2XTTTTNz5szcfPPNeeCBB7LHHnvk6KOPrnfeyiuvnE022SSHHnpoZs6cmVGjRmWppZbKL37xi3k+10orrZTTTz89xx13XF5//fXssssu6dChQyZNmpRbbrklBx98cH7+85+nqqoql1xySXbcccesvfbaGTp0aHr27JmXXnop//rXvzJmzJgkn4fZkuSII47I4MGD06xZswwZMiQHHnhgPvzww2y11VZZbrnl8sYbb+TCCy/M2muvXbuN3cKyxx575Pnnn88ZZ5yRf/7zn9lzzz3Tp0+ffPDBB7nrrrty77335tprr03y+UpiN998c3bdddfssMMOmTRpUi699NL079+/Tlhvyy23zI9//ONccMEFmTBhQrbbbrvU1NTkH//4R7bccsscfvjhjarxrLPOyv33358NNtggBx10UPr3758PP/wwTz/9dO655558+OGHX3n+b3/727z00ks57LDDctddd9WuUDVmzJj89a9/zeabb55zzz233nm77757fv7zn+fnP/95unbtWm/lrM033zyHHHJIzjzzzDzzzDPZdttt06JFi0yYMCE33HBDzj///PzgBz9o1L2WWyXeEwAAACzJhKsAAACAslt55ZWz995756qrrqp37KSTTsr//ve/3Hjjjbn++uuz/fbb584770y3bt0WSC3HH398nnvuuZx55pn55JNPsvXWW+fiiy9O27Zta+dsscUWefTRR3Paaafl//7v/zJt2rT06NEjG2ywQQ455JD5fu7u3bvnkUceyTHHHJMLL7wwn332WQYOHJjbbrstO+yww3xft2fPnnniiSdy7rnn5oYbbshNN92U5s2bZ+DAgbnyyiuzzz77lNx+b5999klVVVVGjRqVyZMnZ/3118///d//pWfPnl/5fMcee2xWWWWV/Pa3v61deal3797Zdttts9NOO9XOGzx4cO6///6MHDky5557bmpqarLSSivVBtmSz1fC+ulPf5rrrrsuf/rTn1IsFjNkyJDsvffeGT16dC6++OJMmTIlPXr0yB577JFTTjllvkNo38Tpp5+erbbaKhdccEEuueSSfPjhh+nSpUu+853v5K9//Wvtfe+333559913c9lll2XMmDHp379//vSnP+WGG27IAw88UOeaV1xxRQYOHJjf//73Ofroo9OpU6est9562WijjRpdX/fu3fPEE0/k1FNPzc0335yLL744Sy21VAYMGFByS84va9++fe69995cfPHF+dOf/pSjjz46xWIxq622WkaNGpXDDjssLVq0qHfecsstl4022igPP/xwDjzwwJJzLr300qy77rq57LLLcvzxx6d58+ZZYYUVsvfee9fbqnJxUYn3BAAAAEuqQrGx64gDAAAAwP/vxBNPzJlnnllyOzwAAAAAWNwt/H/GBwAAAEDF+O9//5ull1663GUAAAAAwAJhW0AAAAAAGu21117LLbfckhtuuCHf+973yl0OAAAAACwQVq4CAAAAoNHGjRuXkSNHZvPNN895551X7nIAAAAAYIEoFIvFYrmLAAAAAAAAAAAAWNRYuQoAAAAAAAAAAKAE4SoAAAAAAAAAAIASmpe7gAWtpqYm77zzTjp06JBCoVDucgAAAAAAAAAAgDIrFov55JNP0qtXr1RVzXt9qooPV73zzjvp3bt3ucsAAAAAAAAAAAAWMW+99VaWW265eR6v+HBVhw4dknz+QnTs2LHM1VBKdXV17r777my77bZp0aJFucsB+Mb0NaDS6GtApdHXgEqjrwGVRE8DKo2+BlSaSuprU6dOTe/evWuzRfNS8eGquVsBduzYUbhqEVVdXZ22bdumY8eOi/0PHkCirwGVR18DKo2+BlQafQ2oJHoaUGn0NaDSVGJfm5stmpd5bxgIAAAAAAAAAACwBBOuAgAAAAAAAAAAKEG4CgAAAAAAAAAAoAThKgAAAAAAAAAAgBKEqwAAAAAAAAAAAEoQrgIAAAAAAAAAAChBuAoAAAAAAAAAAKAE4SoAAAAAAAAAAIAShKsAAAAAAAAAAABKEK4CAAAAAAAAAAAooazhqnHjxmXHHXdMr169UigUcuutt9Y5XiwWc9JJJ6Vnz55p06ZNttlmm0yYMKE8xQIAAAAAAAAAAEuUsoarpk+fnrXWWisXXXRRyePnnHNOLrjgglx66aV5/PHH065duwwePDifffbZQq4UAAAAAAAAAABY0jQv55Nvv/322X777UseKxaLGTVqVH75y19m5513TpJcffXV6d69e2699dYMGTJkYZYKAAAAAAAAAAAsYcoarvoqkyZNyrvvvpttttmmdqxTp07ZYIMN8uijj84zXDVz5szMnDmz9vHUqVOTJNXV1amurl6wRTNf5r4vC+L9mVk9J2ucem+SZNXu7Zv8+gClFIvFfDKtWS569eEUCoVylwPwjelrQKXR14BKo68BlURPAyqNvgZLttN37p+1e3cudxlNakFmPBa2ht7DIhuuevfdd5Mk3bt3rzPevXv32mOlnHnmmRk5cmS98bvvvjtt27Zt2iJpUmPHjm3ya/7tjarM3f3y5femNfn1AeatkP/OmF7uIgCakL4GVBp9Dag0+hpQSfQ0oNLoa7Ckuv+hR/NOp2K5y1ggFkTGY2GbMWNGg+YtsuGq+XXcccflqKOOqn08derU9O7dO9tuu206duxYxsqYl+rq6owdOzaDBg1KixYtmvTa4255IXnnnSTJlfut26TXBpiX2bNn5+mnns46666T5s0r7o9aYAmkrwGVRl8DKo2+BlQSPQ2oNPoaLNkG9OyYzm2bNgdRbgsy47Gwzd0N7+ssst27R48eSZL33nsvPXv2rB1/7733svbaa8/zvFatWqVVq1b1xlu0aLHYv6mVbsG8R1W1322xWo8mvjZAadXV1Zn+ajGbr9rdnz1ARdDXgEqjrwGVRl8DKomeBlQafQ2oVJWQw2lo/VVfP6U8+vbtmx49euTee++tHZs6dWoef/zxbLjhhmWsjMVJMZW5vB4AAAAAAAAAAAteWVeumjZtWiZOnFj7eNKkSXnmmWfStWvXLL/88hkxYkROP/309OvXL3379s2JJ56YXr16ZZdddilf0SxWirJVAAAAAAAAAADMp7KGq8aPH58tt9yy9vFRRx2VJNl3331z5ZVX5he/+EWmT5+egw8+OFOmTMkmm2ySu+66K61bty5XySxmaqSrAAAAAAAAAACYT2UNV22xxRYpfkX4pVAo5NRTT82pp566EKuikshWAQAAAAAAAAAwv6rKXQAsSLJVAAAAAAAAAADML+EqKpptAQEAAAAAAAAAmF/CVVQ22SoAAAAAAAAAAOaTcBUVzcpVAAAAAAAAAADML+EqKppsFQAAAAAAAAAA80u4iopm5SoAAAAAAAAAAOaXcBUVTbQKAAAAAAAAAID5JVxFRbNwFQAAAAAAAAAA80u4igonXQUAAAAAAAAAwPwRrqKi1chWAQAAAAAAAAAwn4SrqGhF+wICAAAAAAAAADCfhKuoaFauAgAAAAAAAABgfglXUdFqrFwFAAAAAAAAAMB8Eq4CAAAAAAAAAAAoQbiKimblKgAAAAAAAAAA5pdwFRVNtgoAAAAAAAAAgPklXEVFE64CAAAAAAAAAGB+CVdR0WwLCAAAAAAAAADA/BKuoqKJVgEAAAAAAAAAML+Eq6hoRStXAQAAAAAAAAAwn4SrqGiyVQAAAAAAAAAAzC/hKiqabBUAAAAAAAAAAPNLuIqKVmPpKgAAAAAAAAAA5pNwFRVNtgoAAAAAAAAAgPklXEVFk60CAAAAAAAAAGB+CVdR0YqWrgIAAAAAAAAAYD4JV1HRaoSrAAAAAAAAAACYT8JVVDTZKgAAAAAAAAAA5pdwFRWtRrgKAAAAAAAAAID5JFxFRStaugoAAAAAAAAAgPkkXEVFk60CAAAAAAAAAGB+NS93AdDUrh//Vn5x43PlLgMAAAAAAAAAgMWclauoOIJVAAAAAAAAAAA0BeEqlgiv/eq75S4BAAAAAAAAAIDFjHAVS4SqqkK5SwAAAAAAAAAAYDEjXAUAAAAAAAAAAFCCcBUAAAAAAAAAAEAJwlUAAAAAAAAAAAAlCFcBAAAAAAAAAACUIFwFAAAAAAAAAABQgnAVAAAAAAAAAABACcJVAAAAAAAAAAAAJQhXAQAAAAAAAAAAlCBcBQAAAAAAAAAAUIJwFQAAAAAAAAAAQAnCVQAAAAAAAAAAACUIVwEAAAAAAAAAAJQgXAUAAAAAAAAAAFCCcBUAAAAAAAAAAEAJwlUAAAAAAAAAAAAlCFcBAAAAAAAAAACUIFwFAAAAAAAAAABQgnAVAAAAAAAAAABACcJVAAAAAAAAAAAAJQhXAQAAAAAAAAAAlCBcBQAAAAAAAAAAUIJwFQAAAAAAAAAAQAnCVQAAAAAAAAAAACUIVwEAAAAAAAAAAJQgXAUAAAAAAAAAAFCCcBUAAAAAAAAAAEAJwlUAAAAAAAAAAAAlCFcBAAAAAAAAAACUIFwFAAAAAAAAAABQgnAVAAAAAAAAAABACcJVAAAAAAAAAAAAJQhXAQAAAAAAAAAAlLBIh6vmzJmTE088MX379k2bNm2y0kor5bTTTkuxWCx3aQAAAAAAAAAAQIVrXu4CvsrZZ5+dSy65JFdddVUGDBiQ8ePHZ+jQoenUqVOOOOKIcpcHAAAAAAAAAABUsEU6XPXII49k5513zg477JAkWWGFFfLnP/85TzzxRJkro9yKxWLmLmBWTFLI//seAAAAAAAAAACawiIdrtpoo40yevTovPLKK1lllVXy7LPP5qGHHsp55503z3NmzpyZmTNn1j6eOnVqkqS6ujrV1dULvGYab+770tD3p1gsZsjlT+bpN6c0+jkAFobG9jWARZ2+BlQafQ2oNPoaUEn0NKDS6GtApamkvtbQeygUi8VFdrGfmpqaHH/88TnnnHPSrFmzzJkzJ2eccUaOO+64eZ5zyimnZOTIkfXGr7322rRt23ZBlstC8tmc5JgnGp4L3KXPnGzZa5H9mAMAAAAAAAAAsJDNmDEjP/rRj/Lxxx+nY8eO85y3SIerrrvuuhx99NH59a9/nQEDBuSZZ57JiBEjct5552XfffcteU6plat69+6d999//ytfCMqnuro6Y8eOzaBBg9KiRYuvnT9t5ux86/T7vnbeM7/cKs2bVaVV86qmKBOgwRrb1wAWdfoaUGn0NaDS6GtAJdHTgEqjrwGVppL62tSpU7P00kt/bbhqkd4W8Oijj86xxx6bIUOGJEnWXHPNvPHGGznzzDPnGa5q1apVWrVqVW+8RYsWi/2bWuka+h41n9Ow63Vu3+YbVgTwzfizB6g0+hpQafQ1oNLoa0Al0dOASqOvAZWmEvpaQ+tfpJf0mTFjRqqq6pbYrFmz1NTUlKkiAAAAAAAAAABgSbFIr1y144475owzzsjyyy+fAQMG5J///GfOO++87L///uUuDQAAAAAAAAAAqHDfOFw1derU3HfffVl11VWz+uqrN0VNtS688MKceOKJOeywwzJ58uT06tUrhxxySE466aQmfR4AAAAAAAAAAIAva3S4avfdd89mm22Www8/PJ9++mnWW2+9vP766ykWi7nuuuuy2267NVlxHTp0yKhRozJq1KgmuyYAAAAAAAAAAEBDVDX2hHHjxmXTTTdNktxyyy0pFouZMmVKLrjggpx++ulNXiAAAAAAAAAAAEA5NDpc9fHHH6dr165Jkrvuuiu77bZb2rZtmx122CETJkxo8gLhy4rlLgAAAAAAAAAAgCVCo8NVvXv3zqOPPprp06fnrrvuyrbbbpsk+eijj9K6desmLxAAAAAAAAAAAKAcmjf2hBEjRmSvvfZK+/bt06dPn2yxxRZJPt8ucM0112zq+qCeQrkLAAAAAAAAAABgidDocNVhhx2WDTbYIG+++WYGDRqUqqrPF79accUVc8YZZzR5gfBltgUEAAAAAAAAAGBhaPS2gKeeempWX3317Lrrrmnfvn3t+FZbbZV77rmnSYsDAAAAAAAAAAAol0aHq0aOHJlp06bVG58xY0ZGjhzZJEXBVylaugoAAAAAAAAAgIWg0eGqYrGYQqFQb/zZZ59N165dm6QoAAAAAAAAAACAcmve0IldunRJoVBIoVDIKqusUidgNWfOnEybNi0/+clPFkiR8EUlsn0AAAAAAAAAANDkGhyuGjVqVIrFYvbff/+MHDkynTp1qj3WsmXLrLDCCtlwww0XSJHwRbYFBAAAAAAAAABgYWhwuGrfffdNkvTt2zcbb7xxmjdv8KkAAAAAAAAAAACLnarGnjB9+vTce++99cbHjBmTO++8s0mKAgAAAAAAAAAAKLdGh6uOPfbYzJkzp954sVjMscce2yRFAQAAAAAAAAAAlFujw1UTJkxI//79642vttpqmThxYpMUBQAAAAAAAAAAUG6NDld16tQpr732Wr3xiRMnpl27dk1SFAAAAAAAAAAAQLk1Oly18847Z8SIEXn11VdrxyZOnJif/exn2WmnnZq0OCipWO4CAAAAAAAAAABYEjQ6XHXOOeekXbt2WW211dK3b9/07ds3q6++epZaaqn85je/WRA1AgAAAAAAAAAALHTNG3tCp06d8sgjj2Ts2LF59tln06ZNmwwcODCbbbbZgqgPAAAAAAAAAACgLBodrkqSQqGQbbfdNptttllatWqVQqHQ1HUBAAAAAAAAAACUVaO3Baypqclpp52WZZddNu3bt8+kSZOSJCeeeGJ+//vfN3mBAAAAAAAAAAAA5dDocNXpp5+eK6+8Muecc05atmxZO77GGmvk8ssvb9LioJRiiuUuAQAAAAAAAACAJUCjw1VXX311Ro8enb322ivNmjWrHV9rrbXy0ksvNWlxAAAAAAAAAAAA5dLocNXbb7+dlVdeud54TU1Nqqurm6QoAAAAAAAAAACAcmt0uKp///75xz/+UW/8xhtvzLe+9a0mKQoAAAAAAAAAAKDcmjf2hJNOOin77rtv3n777dTU1OTmm2/Oyy+/nKuvvjq33377gqgRAAAAAAAAAABgoWv0ylU777xzbrvtttxzzz1p165dTjrppLz44ou57bbbMmjQoAVRIwAAAAAAAAAAwELX6JWrkmTTTTfN2LFjm7oWaJBisdwVAAAAAAAAAACwJGj0ylUAAAAAAAAAAABLggatXNW1a9e88sorWXrppdOlS5cUCoV5zm3fvn0GDBiQs88+OwMHDmyyQgEAAAAAAAAAABamBoWrfvvb36ZDhw5JklGjRn3l3JkzZ+aOO+7I0KFD89RTT33jAuHL7AoIAAAAAAAAAMDC0KBw1b777lvy+3nZfvvts+66685/VfAFxWIxUz+dnWbNCpk1uyafVs8pd0kAAAAAAAAAACwBGhSuKmX8+PF58cUXkySrr7561ltvvdpjvXv3zuTJk795dZDk5L/9K1c/+ka5ywAAAAAAAAAAYAnT6HDVf/7zn+y55555+OGH07lz5yTJlClTstFGG+W6667Lcsst19Q1soSbn2DVebuvtQAqAQAAAAAAAABgSdLocNWBBx6Y6urqvPjii1l11VWTJC+//HKGDh2aAw88MHfddVeTFwml7LXB8jlj1zXLXQYAAAAAAAAAABWq0eGqBx98MI888khtsCpJVl111Vx44YXZdNNNm7Q4AAAAAAAAAACAcqlq7Am9e/dOdXV1vfE5c+akV69eTVIUAAAAAAAAAABAuTU6XPXrX/86P/3pTzN+/PjasfHjx2f48OH5zW9+06TFAQAAAAAAAAAAlEuDtgXs0qVLCoVC7ePp06dngw02SPPmn58+e/bsNG/ePPvvv3922WWXBVIoAAAAAAAAAADAwtSgcNWoUaMWcBkAAAAAAAAAAACLlgaFq/bdd98FXQcAAAAAAAAAAMAipUHhqi96++23c9NNN+WVV15Jkqy66qr5/ve/n2WXXbbJiwMAAAAAAAAAACiXRoWrLr744hx11FGZNWtWOnbsmCSZOnVqjj766Jx33nk57LDDFkiRAAAAAAAAAAAAC1tVQyf+/e9/zxFHHJHDDz88b7/9dqZMmZIpU6bk7bffzmGHHZbhw4fnjjvuWJC1AgAAAAAAAAAALDQNXrnq17/+dY499ticfvrpdcZ79uyZ8847L23bts0555yT7373u01eJAAAAAAAAAAAwMLW4JWrnn766fz4xz+e5/Ef//jHefrpp5ukKAAAAAAAAAAAgHJrcLhqzpw5adGixTyPt2jRInPmzGmSoqAhCoVyVwAAAAAAAAAAQCVrcLhqwIAB+etf/zrP47feemsGDBjQJEUBAAAAAAAAAACUW/OGThw2bFgOPfTQtGrVKgcffHCaN//81NmzZ+eyyy7LL3/5y1x88cULrFAAAAAAAAAAAICFqcHhqn333TfPP/98Dj/88Bx33HFZaaWVUiwW89prr2XatGk54ogjst9++y3AUgEAAAAAAAAAABaeBoerkuQ3v/lNfvCDH+TPf/5zJkyYkCTZfPPNM2TIkHznO99ZIAUCAAAAAAAAAACUQ6PCVUnyne98R5AKAAAAAAAAAACoeFXlLgAAAAAAAAAAAGBRJFwFAAAAAAAAAABQgnAVAAAAAAAAAABACcJVAAAAAAAAAAAAJQhXAQAAAAAAAAAAlNC8IZO+9a1vpVAoNOiCTz/99DcqCAAAAAAAAAAAYFHQoHDVLrvsUvv9Z599losvvjj9+/fPhhtumCR57LHH8q9//SuHHXbYAikSAAAAAAAAAABgYWtQuOrkk0+u/f7AAw/MEUcckdNOO63enLfeeqtpq4OvUEjDVlMDAAAAAAAAAID5UdXYE2644Ybss88+9cb33nvv3HTTTU1SFAAAAAAAAAAAQLk1OlzVpk2bPPzww/XGH3744bRu3bpJigIAAAAAAAAAACi3Bm0L+EUjRozIoYcemqeffjrrr79+kuTxxx/PH/7wh5x44olNXiAAAAAAAAAAAEA5NDpcdeyxx2bFFVfM+eefnz/96U9JktVXXz1XXHFFdt999yYvEAAAAAAAAAAAoBwaHa5Kkt13312QCgAAAAAAAAAAqGhV83PSlClTcvnll+f444/Phx9+mCR5+umn8/bbbzdpcQAAAAAAAAAAAOXS6JWrnnvuuWyzzTbp1KlTXn/99Rx44IHp2rVrbr755rz55pu5+uqrF0SdAAAAAAAAAAAAC1WjV6466qijst9++2XChAlp3bp17fh3v/vdjBs3rkmLAwAAAAAAAAAAKJdGh6uefPLJHHLIIfXGl1122bz77rtNUtQXvf3229l7772z1FJLpU2bNllzzTUzfvz4Jn8eAAAAAAAAAACAL2r0toCtWrXK1KlT642/8sorWWaZZZqkqLk++uijbLzxxtlyyy1z5513ZplllsmECRPSpUuXJn0eAAAAAAAAAACAL2t0uGqnnXbKqaeemuuvvz5JUigU8uabb+aYY47Jbrvt1qTFnX322endu3euuOKK2rG+ffs26XOwaKupKZa7BAAAAAAAAAAAllCNDlede+65+cEPfpBu3brl008/zeabb5533303G264Yc4444wmLe5vf/tbBg8enB/+8Id58MEHs+yyy+awww7LQQcdNM9zZs6cmZkzZ9Y+nrvKVnV1daqrq5u0PprG3Pel1Psz8vYX531iscZ7CiySvqqvASyO9DWg0uhrQKXR14BKoqcBlUZfAypNJfW1ht5DoVgsztfSQA899FCee+65TJs2Leuss0622Wab+bnMV2rdunWS5KijjsoPf/jDPPnkkxk+fHguvfTS7LvvviXPOeWUUzJy5Mh649dee23atm3b5DWyYA1/tHT+b4X2xey6wpys0GEhFwQAAAAAAAAAwGJvxowZ+dGPfpSPP/44HTt2nOe8+Q5XLQwtW7bMeuutl0ceeaR27IgjjsiTTz6ZRx99tOQ5pVau6t27d95///2vfCEon+rq6owdOzaDBg1KixYt6hzrd+Ldtd/fPmzDrNpDmgpY9H1VXwNYHOlrQKXR14BKo68BlURPAyqNvgZUmkrqa1OnTs3SSy/9teGqRm8LmCT33ntv7r333kyePDk1NTV1jv3hD3+Yn0uW1LNnz/Tv37/O2Oqrr56bbrppnue0atUqrVq1qjfeokWLxf5NrXRf9x41b9HcewgsVvzZA1QafQ2oNPoaUGn0NaCS6GlApdHXgEpTCX2tofU3Olw1cuTInHrqqVlvvfXSs2fPFAqFRhfXUBtvvHFefvnlOmOvvPJK+vTps8Cek0VXIQvuswYAAAAAAAAAAF/W6HDVpZdemiuvvDI//vGPF0Q9dRx55JHZaKON8qtf/Sq77757nnjiiYwePTqjR49e4M8NAAAAAAAAAAAs2aoae8KsWbOy0UYbLYha6vn2t7+dW265JX/+85+zxhpr5LTTTsuoUaOy1157LZTnBwAAAAAAAAAAllyNDlcdeOCBufbaaxdELSV973vfy/PPP5/PPvssL774Yg466KCF9twsWhbgDpQAAAAAAAAAAFBPg7YFPOqoo2q/r6mpyejRo3PPPfdk4MCBadGiRZ255513XtNWCAAAAAAAAAAAUAYNClf985//rPN47bXXTpK88MILdcYLlhYCAAAAAAAAAAAqRIPCVffff/+CrgO+lugeAAAAAAAAAAALU1VjT/j444/z4Ycf1hv/8MMPM3Xq1CYpCgAAAAAAAAAAoNwaHa4aMmRIrrvuunrj119/fYYMGdIkRUEpdp0EAAAAAAAAAGBhanS46vHHH8+WW25Zb3yLLbbI448/3iRFAQAAAAAAAAAAlFujw1UzZ87M7Nmz641XV1fn008/bZKiAAAAAAAAAAAAyq3R4ar1118/o0ePrjd+6aWXZt11122SoqA0+wICAAAAAAAAALDwNG/sCaeffnq22WabPPvss9l6662TJPfee2+efPLJ3H333U1eIAAAAAAAAAAAQDk0euWqjTfeOI8++mh69+6d66+/PrfddltWXnnlPPfcc9l0000XRI0AAAAAAAAAAAALXaNXrkqStddeO9dcc01T1wJfqWBXQAAAAAAAAAAAFqL5ClfN9dlnn2XWrFl1xjp27PiNCgIAAAAAAAAAAFgUNHpbwBkzZuTwww9Pt27d0q5du3Tp0qXOFwAAAAAAAAAAQCVodLjq6KOPzn333ZdLLrkkrVq1yuWXX56RI0emV69eufrqqxdEjZAksSsgAAAAAAAAAAALU6O3Bbztttty9dVXZ4sttsjQoUOz6aabZuWVV06fPn1yzTXXZK+99loQdQIAAAAAAAAAACxUjV656sMPP8yKK66YJOnYsWM+/PDDJMkmm2yScePGNW11AAAAAAAAAAAAZdLocNWKK66YSZMmJUlWW221XH/99Uk+X9Gqc+fOTVocfFGhYGNAAAAAAAAAAAAWnkaHq4YOHZpnn302SXLsscfmoosuSuvWrXPkkUfm6KOPbvICAQAAAAAAAAAAyqF5Y0848sgja7/fZptt8tJLL+Wpp57KyiuvnIEDBzZpcfBF1q0CAAAAAAAAAGBhanS46sv69OmTPn36NEUtAAAAAAAAAAAAi4wGbwt43333pX///pk6dWq9Yx9//HEGDBiQf/zjH01aHAAAAAAAAAAAQLk0OFw1atSoHHTQQenYsWO9Y506dcohhxyS8847r0mLgy8q2BcQAAAAAAAAAICFqMHhqmeffTbbbbfdPI9vu+22eeqpp5qkKAAAAAAAAAAAgHJrcLjqvffeS4sWLeZ5vHnz5vnf//7XJEUBAAAAAAAAAACUW4PDVcsuu2xeeOGFeR5/7rnn0rNnzyYpCkopxL6AAAAAAAAAAAAsPA0OV333u9/NiSeemM8++6zesU8//TQnn3xyvve97zVpcQAAAAAAAAAAAOXSvKETf/nLX+bmm2/OKqusksMPPzyrrrpqkuSll17KRRddlDlz5uSEE05YYIUCAAAAAAAAAAAsTA0OV3Xv3j2PPPJIDj300Bx33HEpFotJkkKhkMGDB+eiiy5K9+7dF1ihULArIAAAAAAAAAAAC1GDw1VJ0qdPn9xxxx356KOPMnHixBSLxfTr1y9dunRZUPUBAAAAAAAAAACURaPCVXN16dIl3/72t5u6FgAAAAAAAAAAgEXGfIWrYEF7/j8fZ87/v/UkAAAAAAAAAACUg3AVi5x3pnyaHf/voXrjLZpVlaEaAAAAAAAAAACWVNIqLHImTp5Wb6xz2xbp0al1GaoBAAAAAAAAAGBJ1aBw1TrrrJOPPvooSXLqqadmxowZC7QolmylNgP82aBVFnodAAAAAAAAAAAs2RoUrnrxxRczffr0JMnIkSMzbVr9lYWgqRSL9eNVhUKhDJUAAAAAAAAAALAka96QSWuvvXaGDh2aTTbZJMViMb/5zW/Svn37knNPOumkJi2QJU+JbFWaVQlXAQAAAAAAAACwcDUoXHXllVfm5JNPzu23355CoZA777wzzZvXP7VQKAhX8Y0VS2wMKFsFAAAAAAAAAMDC1qBw1aqrrprrrrsuSVJVVZV777033bp1W6CFseQqtXKVbQEBAAAAAAAAAFjYGhSu+qKampoFUQfUKrktoHAVAAAAAAAAAAALWaPDVUny6quvZtSoUXnxxReTJP3798/w4cOz0korNWlxLJlKZKtSVbXQywAAAAAAAAAAYAnX6MjKmDFj0r9//zzxxBMZOHBgBg4cmMcffzwDBgzI2LFjF0SNLGFqSixdVWXlKgAAAAAAAAAAFrJGr1x17LHH5sgjj8xZZ51Vb/yYY47JoEGDmqw4lkyltgUUrgIAAAAAAAAAYGFr9MpVL774Yg444IB64/vvv3/+/e9/N0lRLOmsXAUAAAAAAAAAQPk1Oly1zDLL5Jlnnqk3/swzz6Rbt25NURNLuFIrVzVr9CcVAAAAAAAAAAC+mUZvC3jQQQfl4IMPzmuvvZaNNtooSfLwww/n7LPPzlFHHdXkBbLkKZGtSsHKVQAAAAAAAAAALGSNDledeOKJ6dChQ84999wcd9xxSZJevXrllFNOyRFHHNHkBbLkqSmxdFUz4SoAAAAAAAAAABayRoerCoVCjjzyyBx55JH55JNPkiQdOnRo8sJYcpXaFrDKtoAAAAAAAAAAACxkjQ5XfZFQFQtCqW0Bq6xcBQAAAAAAAADAQmY9IBY5xRJLVwlXAQAAAAAAAACwsAlXsVgQrgIAAAAAAAAAYGETrmKRU1Nq5SqfVAAAAAAAAAAAFrJGRVaqq6uz9dZbZ8KECQuqHkiJbJWVqwAAAAAAAAAAWOgaFa5q0aJFnnvuuQVVCyQpHa5qViVcBQAAAAAAAADAwtXozdb23nvv/P73v18QtUCSpES2KrJVAAAAAAAAAAAsbM0be8Ls2bPzhz/8Iffcc0/WXXfdtGvXrs7x8847r8mKY8lULLF0VcG2gAAAAAAAAAAALGSNDle98MILWWeddZIkr7zySp1jAjA0hZLbAvpsAQAAAAAAAACwkDU6XHX//fcviDqgVrHExoBVwlUAAAAAAAAAACxkVfN74sSJEzNmzJh8+umnSUpv5Qbzo9RHqWq+P6kAAAAAAAAAADB/Gh1Z+eCDD7L11ltnlVVWyXe/+93897//TZIccMAB+dnPftbkBbLkKRXTs3IVAAAAAAAAAAALW6PDVUceeWRatGiRN998M23btq0d32OPPXLXXXc1aXEsmWpKLF3VrEq4CgAAAAAAAACAhat5Y0+4++67M2bMmCy33HJ1xvv165c33nijyQpjyVVyW0DZKgAAAAAAAAAAFrJGr1w1ffr0OitWzfXhhx+mVatWTVIUS7ZS2wIWbAsIAAAAAAAAAMBC1uhw1aabbpqrr7669nGhUEhNTU3OOeecbLnllk1aHEuoUtsCClcBAAAAAAAAALCQNXpbwHPOOSdbb711xo8fn1mzZuUXv/hF/vWvf+XDDz/Mww8/vCBqZAlTauWqKuEqAAAAAAAAAAAWskavXLXGGmvklVdeySabbJKdd94506dPz/e///3885//zEorrbQgamQJU1NTP15V1ehPKgAAAAAAAAAAfDONXrkqSTp16pQTTjihqWuBJFauAgAAAAAAAABg0TBf4aqPPvoov//97/Piiy8mSfr375+hQ4ema9euTVocS6ZiiXSVcBUAAAAAAAAAAAtbozdbGzduXFZYYYVccMEF+eijj/LRRx/lggsuSN++fTNu3LgFUWOts846K4VCISNGjFigz0N5lVy5yraAAAAAAAAAAAAsZI1euWrYsGHZY489cskll6RZs2ZJkjlz5uSwww7LsGHD8vzzzzd5kUny5JNP5rLLLsvAgQMXyPVZdBRLLF1l5SoAAAAAAAAAABa2Rq8HNHHixPzsZz+rDVYlSbNmzXLUUUdl4sSJTVrcXNOmTctee+2V3/3ud+nSpcsCeQ4WDY+++kFO//uL9cabCVcBAAAAAAAAALCQNXrlqnXWWScvvvhiVl111TrjL774YtZaa60mK+yLhg0blh122CHbbLNNTj/99K+cO3PmzMycObP28dSpU5Mk1dXVqa6uXiD18c3MfV+qq6uz5+8eKzmnUJzj/QMWG1/sawCVQF8DKo2+BlQafQ2oJHoaUGn0NaDSVFJfa+g9NChc9dxzz9V+f8QRR2T48OGZOHFivvOd7yRJHnvssVx00UU566yz5qPUr3bdddfl6aef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3ngjO+64Y7p06ZJ27dplwIABueOOO+Z5j1+uqVAo5PLLL8+uu+6atm3bpl+/fvnb3/42z/OLxWL222+/9OvXL//4xz+yww47pG/fvll77bVz8skn569//Wvt3GOOOSarrLJK2rZtmxVXXDEnnnhiqqurG3S/c82YMSP7779/OnTokOWXXz6jR4+uc/ytt97K7rvvns6dO6dr167Zeeed8/rrr8+z/qbQfIFeHQAAAAAAAACAJcqn1XPS/6QxZXnuf586OG1bfn0c5sMPP8yYMWNyxhlnpE2bNnWO9ejRI3vttVf+8pe/5OKLL64NNv3617/O8ccfn5EjR2bMmDEZPnx4VllllQwaNKjkc/zwhz9MmzZtcuedd6ZTp0657LLLsvXWW+eVV15J165d8/e//z277rprTjjhhFx99dWZNWtWbVDq5ptvzlprrZWDDz44Bx10UO01hw0bllmzZmXcuHFp165d/v3vf6d9+/aNeo1GjhyZc845J7/+9a9z4YUXZq+99sobb7yRrl271pv7zDPP5F//+leuvfbaVFVVpaamps7xzp07137foUOHXHnllenVq1eef/75HHTQQenQoUN+8YtfJMlX3u9c5557bk477bQcf/zxufHGG3PooYdm8803z6qrrprq6uoMHjw4G264Yf7xj3+kefPmOf3007PddtvlueeeS8uWLRv1OjSUcBUAAAAAAAAAAEuUCRMmpFgsZvXVVy95fPXVV89HH32U//3vf+nWrVuSZOONN86xxx6bJFlllVXy8MMP57e//W3JcNVDDz2UJ554IpMnT06rVq2SJL/5zW9y66235sYbb8zBBx+cM844I0OGDMnIkSNrz1trrbWSJF27dk2zZs3SoUOH9OjRo/b4m2++md122y1rrrlmkmTFFVds9L3vt99+2XPPPZMkv/rVr3LBBRfkiSeeyHbbbVfydUqS1VZb7Wuv+8tf/rL2+xVWWCE///nPc91119WGq77qfuf67ne/m8MOOyzJ5yth/fa3v83999+fVVddNX/5y19SU1OTyy+/vDbwdsUVV6Rz58554IEHsu222zbmZWgw4SoAAAAAAAAAAJpMmxbN8u9TB5ftuRujMdsIbrjhhvUef3HLvS969tlnM23atCy11FJ1xj/99NO8+uqrST5fFeqLq1I1xBFHHJFDDz00d999d7bZZpvstttuGThwYKOu8cX57dq1S8eOHTN58uSScxvz+vzlL3/JBRdckFdffTXTpk3L7Nmz07Fjx9rjDbnfL9ZWKBTSo0eP2tqeffbZTJw4MR06dKhzzmeffVb7mi4IwlUAAAAAAAAAADSZQqHQoK35ymnllVdOoVDIiy++mF133bXe8RdffDFdunTJMsssM1/XnzZtWnr27JkHHnig3rG5W+l9eTvChjjwwAMzePDg/P3vf8/dd9+dM888M+eee25++tOfNvgaLVq0qPO4UCjU2+5vrlVWWSVJ8tJLL+Vb3/rWPK/56KOPZq+99srIkSMzePDgdOrUKdddd13OPffc2jkNud+vqm3atGlZd911c80119Q7b37fp4aoWmBXhgbafJWly10CAAAAAAAAALAEWWqppTJo0KBcfPHF+fTTT+sce/fdd3PNNddkjz32qN1+Lkkee+yxOvMee+yxeW4ruM466+Tdd99N8+bNs/LKK9f5Wnrpz3MSAwcOzL333jvPGlu2bJk5c+bUG+/du3d+8pOf5Oabb87Pfvaz/O53v2vwfTfW2muvnf79++fcc88tGcCaMmVKkuSRRx5Jnz59csIJJ2S99dZLv3798sYbb9SZ+3X3+3XWWWedTJgwId26dav3mnbq1Gm+r/t1hKsou5E7rp4f9J2TW37ynXKXAgAAAAAAAAAsIf7v//4vM2fOzODBgzNu3Li89dZbueuuuzJo0KAsu+yyOeOMM+rMf/jhh3POOefklVdeyUUXXZQbbrghw4cPL3ntbbbZJhtuuGF22WWX3H333Xn99dfzyCOP5IQTTsj48eOTJCeffHL+/Oc/5+STT86LL76Y559/PmeffXbtNVZYYYWMGzcub7/9dt5///0kyYgRIzJmzJhMmjQpTz/9dO6///55BryaQqFQyBVXXJFXXnklm266ae644468/vrree6553LGGWdk5513TpL069cvb775Zq677rq8+uqrueCCC3LLLbfUudbX3e/X2WuvvbL00ktn5513zj/+8Y9MmjQpDzzwQI444oj85z//adL7/iLhKspu2c5tsmmPYtZYtuPXTwYAAAAAAAAAaAL9+vXL+PHjs+KKK2b33XfPSiutlIMPPjhbbrllHn300XTt2rXO/J/97GcZP358vvWtb+X000/Peeedl8GDB5e8dqFQyB133JHNNtssQ4cOzSqrrJIh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/vOfi8Visfjvf/+7mKT45JNP1s658847i4VCofj2228vtNoBSpk8eXIxSfHBBx8sFouf97AWLVoUb7jhhto5L774YjFJ8dFHHy0Wi8XiHXfcUayqqiq+++67tXMuueSSYseOHYszZ85cuDcAUEKXLl2Kl19+uZ4GLLY++eSTYr9+/Ypjx44tbr755sXhw4cXi0W/qwGLn5NPPrm41lprlTympwGLo2OOOaa4ySabzPO4vzMAFnfDhw8vrrTSSsWamhq/rxWLRStXUTazZs3KU089lW222aZ2rKqqKttss00effTRMlYG0HiTJk3Ku+++W6enderUKRtssEFtT3v00UfTuXPnrLfeerVzttlmm1RVVeXxxx9f6DUDfNHHH3+cJOnatWuS5Kmnnkp1dXWdvrbaaqtl+eWXr9PX1lxzzXTv3r12zuDBgzN16tTalWIAymHOnDm57rrrMn369Gy44YZ6GrDYGjZsWHbYYYc6/SvxuxqweJowYUJ69eqVFVdcMXvttVfefPPNJHoasHj629/+lvXWWy8//OEP061bt3zrW9/K7373u9rj/s4AWJzNmjUrf/rTn7L//vunUCj4fS22BaSM3n///cyZM6fOD1eSdO/ePe+++26ZqgKYP3P71lf1tHfffTfdunWrc7x58+bp2rWrvgeUVU1NTUaMGJGNN944a6yxRpLPe1bLli3TuXPnOnO/3NdK9b25xwAWtueffz7t27dPq1at8pOf/CS33HJL+vfvr6cBi6XrrrsuTz/9dM4888x6x/Q1YHGzwQYb5Morr8xdd92VSy65JJMmTcqmm26aTz75RE8DFkuvvfZaLrnkkvTr1y9jxozJoYcemiOOOCJXXXVVEn9nACzebr311kyZMiX77bdfEv8NmiTNy10AAABQXsOGDcsLL7yQhx56qNylAHwjq666ap555pl8/PHHufHGG7PvvvvmwQcfLHdZAI321ltvZfjw4Rk7dmxat25d7nIAvrHtt9++9vuBAwdmgw02SJ8+fXL99denTZs2ZawMYP7U1NRkvfXWy69+9askybe+9a288MILufTSS7PvvvuWuTqAb+b3v/99tt9++/Tq1avcpSwyrFxF2Sy99NJp1qxZ3nvvvTrj7733Xnr06FGmqgDmz9y+9VU9rUePHpk8eXKd47Nnz86HH36o7wFlc/jhh+f222/P/fffn+WWW652vEePHpk1a1amTJlSZ/6X+1qpvjf3GMDC1rJly6y88spZd911c+aZZ2attdbK+eefr6cBi52nnnoqkydPzjrrrJPmzZunefPmefDBB3PBBRekefPm6d69u74GLNY6d+6cVVZZJRMnTvS7GrBY6tmzZ/r3719nbPXVV6/d8tTfGQCLqzfeeCP33HNPDjzwwNoxv68JV1FGLVu2zLrrrpt77723dqympib33ntvNtxwwzJWBtB4ffv2TY8ePer0tKlTp+bxxx+v7WkbbrhhpkyZkqeeeqp2zn333ZeamppssMEGC71mYMlWLBZz+OGH55Zbbsl9992Xvn371jm+7rrrpkWLFnX62ssvv5w333yzTl97/vnn6/xPoLFjx6Zjx471/ucSQDnU1NRk5syZehqw2Nl6663z/PPP55lnnqn9Wm+99bLXXnvVfq+vAYuzadOm5dVXX03Pnj39rgYsljbeeOO8/PLLdcZeeeWV9OnTJ4m/MwAWX1dccUW6deuWHXbYoXbM72u2BaTMjjrqqOy7775Zb731sv7662fUqFGZPn16hg4dWu7SAOqZNm1aJk6cWPt40qRJeeaZZ9K1a9csv/zyGTFiRE4//fT069cvffv2zYknnphevXpll112SfL5v1rZbrvtctBBB+XSSy9NdXV1Dj/88AwZMsSymsBCN2zYsFx77bX561//mg4dOtTued6pU6e0adMmnTp1ygEHHJCjjjoqXbt2TceOHfPTn/40G264Yb7zne8kSbbddtv0798/P/7xj3POOefk3XffzS9/+csMGzYsrVq1KuftAUug4447Lttvv32WX375fPLJJ7n22mvzwAMPZMyYMXoasNjp0KFD1lhjjTpj7dq1y1JLLVU7rq8Bi5Of//zn2XHHHdOnT5+88847Ofnkk9OsWbPsueeeflcDFktHHnlkNtpoo/zqV7/K7rvvnieeeCKjR4/O6NGjkySFQsHfGQCLnZqamlxxxRXZd99907z5/4sT+X0tSRHK7MILLywuv/zyxZYtWxbXX3/94mOPPVbukgBKuv/++4tJ6n3tu+++xWKxWKypqSmeeOKJxe7duxdbtWpV3HrrrYsvv/xynWt88MEHxT333LPYvn37YseOHYtDhw4tfvLJJ2W4G2BJV6qfJSleccUVtXM+/fTT4mGHHVbs0qVLsW3btsVdd921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",
"text/plain": [
"<Figure size 3000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Extract recorded data for plotting\n",
"times, cache_sizes = zip(*cache.cache_size_over_time)\n",
"\n",
"# Plot the cache size over time\n",
"plt.figure(figsize=(30, 5))\n",
"plt.plot(times, cache_sizes, label=\"Objects in Cache\")\n",
"plt.xlabel(\"Time (s)\")\n",
"plt.ylabel(\"Number of Cached Objects\")\n",
"plt.title(\"Number of Objects in Cache Over Time\")\n",
"plt.legend()\n",
"plt.grid(True)\n",
"plt.savefig(f\"{TEMP_BASE_DIR}/objects_in_cache_over_time.pdf\")\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "f30a0497-9b2e-4ea9-8ebf-6687de19aaa9",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAArMAAAIjCAYAAAAQgZNYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABDjklEQVR4nO3de1xVVf7/8fcB5YAaF0NBkMRb3hPTkbDUalA0s5zpoo4TaFbWWGZMF+0iXvqKpZVTWX7zm1p9pzQvWTOZZqSZSlpe8j4ZaZYJispFTVBYvz/6eb4dAYUjcFz6ej4e5zGetdfe+7PX2R7fs1t7H4cxxggAAACwkI+3CwAAAAA8RZgFAACAtQizAAAAsBZhFgAAANYizAIAAMBahFkAAABYizALAAAAaxFmAQAAYC3CLAAAAKxFmAWAKvD111+rS5cuql27thwOhzZt2uTtktxER0fr5ptv9nh9h8OhsWPHVl5B5bRnzx45HA5NmTLF420MHjxY0dHRlVZTZW+vLLNnz5bD4dCePXtcbef7OQIXA8IsYLFt27bpr3/9qyIjI+V0OhUREaFBgwZp27Zt3i7tknby5EndcccdOnz4sF566SW98847atSokbfLAoCLUg1vFwDAMwsXLtTAgQNVt25dDR06VI0bN9aePXv05ptvav78+ZozZ47+9Kc/ebvMS1JGRoZ+/PFHzZgxQ/fcc4+3y0EVmzFjhoqLi71dBnDJIswCFsrIyNBdd92lJk2aaOXKlapXr55r2cMPP6yuXbvqrrvu0ubNm9WkSRMvVlrS8ePHVatWLW+XUaUOHDggSQoODvZuIagWNWvW9HYJwCWNaQaAhSZPnqzjx4/rjTfecAuykhQaGqr//u//1rFjx/T888+7Ldu3b5+GDh2qiIgIOZ1ONW7cWA888IAKCwtdfXJycvTII48oOjpaTqdTDRs2VGJiorKzsyWVPm9PklasWCGHw6EVK1a42q6//nq1bdtW69evV7du3VSrVi09+eSTkqQPP/xQffr0cdXStGlTTZgwQUVFRW7bPb2N7du364YbblCtWrUUGRlZ4tgk6cSJExo7dqyuvPJK+fv7q0GDBvrzn/+sjIwMV5/i4mJNnTpVbdq0kb+/v8LCwjRs2DAdOXKkXGP/+eefq2vXrqpdu7aCg4N16623aseOHa7lgwcPVvfu3SVJd9xxhxwOh66//vqzbjMnJ0cjR45UVFSUnE6nmjVrpueee67E1b4pU6aoS5cuuvzyyxUQEKCOHTtq/vz5pW7zf//3f9W5c2fVqlVLISEh6tatmz799NMS/VatWqXOnTvL399fTZo00dtvv12ucTjTjz/+qL/97W9q0aKFAgICdPnll+uOO+4ocZ6cPn9WrVqlESNGqF69egoODtawYcNUWFionJwcJSYmKiQkRCEhIXr88cdljCl1ny+99JIaNWqkgIAAde/eXVu3bi3RZ9GiRWrbtq38/f3Vtm1bffDBB6VuqyJje6Yz58z+fl7vG2+8oaZNm8rpdOoPf/iDvv7663Jtc9u2bbrxxhsVEBCghg0b6tlnnz3r1d9PP/1UMTEx8vf3V+vWrbVw4cJy7Qe4GHBlFrDQv/71L0VHR6tr166lLu/WrZuio6P18ccfu9p++eUXde7cWTk5ObrvvvvUsmVL7du3T/Pnz9fx48fl5+eno0ePqmvXrtqxY4fuvvtuXX311crOztZHH32kn3/+WaGhoRWu9dChQ+rdu7cGDBigv/71rwoLC5P0W6ipU6eOkpOTVadOHX3++ecaM2aM8vLyNHnyZLdtHDlyRL169dKf//xn3XnnnZo/f76eeOIJtWvXTr1795YkFRUV6eabb1ZaWpoGDBighx9+WPn5+Vq2bJm2bt2qpk2bSpKGDRum2bNna8iQIRoxYoR2796tV199VRs3btTq1avPepXts88+U+/evdWkSRONHTtWv/76q1555RVde+212rBhg6KjozVs2DBFRkZq4sSJGjFihP7whz+4jrk0x48fV/fu3bVv3z4NGzZMV1xxhdasWaPRo0dr//79mjp1qqvvP/7xD91yyy0aNGiQCgsLNWfOHN1xxx3697//rT59+rj6jRs3TmPHjlWXLl00fvx4+fn5ae3atfr888/Vs2dPV7/vv/9et99+u4YOHaqkpCTNnDlTgwcPVseOHdWmTZvyf8j67Ya3NWvWaMCAAWrYsKH27Nmj119/Xddff722b99e4mr8Qw89pPDwcI0bN05fffWV3njjDQUHB2vNmjW64oorNHHiRC1evFiTJ09W27ZtlZiY6Lb+22+/rfz8fA0fPlwnTpzQP/7xD914443asmWLa7w//fRT3XbbbWrdurVSU1N16NAhDRkyRA0bNixRf3nHtiLeffdd5efna9iwYXI4HHr++ef15z//WT/88MNZz7PMzEzdcMMNOnXqlEaNGqXatWvrjTfeUEBAQKn9d+3apf79++v+++9XUlKSZs2apTvuuENLlixRjx49PKodsIoBYJWcnBwjydx6661n7XfLLbcYSSYvL88YY0xiYqLx8fExX3/9dYm+xcXFxhhjxowZYySZhQsXltln1qxZRpLZvXu32/Lly5cbSWb58uWutu7duxtJZvr06SW2d/z48RJtw4YNM7Vq1TInTpwosY23337b1VZQUGDCw8PNbbfd5mqbOXOmkWRefPHFMmv/8ssvjSTzz3/+0235kiVLSm0/U0xMjKlfv745dOiQq+3bb781Pj4+JjEx0dV2eizmzZt31u0ZY8yECRNM7dq1zXfffefWPmrUKOPr62v27t3rajtzzAoLC03btm3NjTfe6GrbtWuX8fHxMX/6059MUVGRW//T42CMMY0aNTKSzMqVK11tBw4cME6n0/z9738/Z92STEpKSpm1GWNMenp6ic/u9PmTkJDgVk9cXJxxOBzm/vvvd7WdOnXKNGzY0HTv3t3Vtnv3biPJBAQEmJ9//tnVvnbtWiPJPPLII662mJgY06BBA5OTk+Nq+/TTT40k06hRI7dayzO2ZUlKSnLb3ukaL7/8cnP48GFX+4cffmgkmX/9619n3d7IkSONJLN27VpX24EDB0xQUFCJv3unP8cFCxa42nJzc02DBg1Mhw4dzlk7cDFgmgFgmfz8fEnSZZdddtZ+p5fn5eWpuLhYixYtUt++fdWpU6cSfR0OhyRpwYIFat++fak3jp3uU1FOp1NDhgwp0f77q0z5+fnKzs5W165ddfz4ce3cudOtb506dfTXv/7V9d7Pz0+dO3fWDz/84GpbsGCBQkND9dBDD5VZ+7x58xQUFKQePXooOzvb9erYsaPq1Kmj5cuXl3kc+/fv16ZNmzR48GDVrVvX1X7VVVepR48eWrx4cTlGo6R58+apa9euCgkJcaspPj5eRUVFWrlypavv78fsyJEjys3NVdeuXbVhwwZX+6JFi1RcXKwxY8bIx8f9K/7Mz7B169ZuV/fr1aunFi1auI1ref2+tpMnT+rQoUNq1qyZgoOD3eo7bejQoW71xMbGyhijoUOHutp8fX3VqVOnUuvp16+fIiMjXe87d+6s2NhY1+dw+vNKSkpSUFCQq1+PHj3UunXrs9Zf1thWVP/+/RUSEuJ6f3qszzW+ixcv1jXXXKPOnTu72urVq6dBgwaV2j8iIsLt72xgYKASExO1ceNGZWZmelw/YAumGQCWOR1ST4fasvw+9B48eFB5eXlq27btWdfJyMjQbbfdVjmF/n+RkZHy8/Mr0b5t2zY9/fTT+vzzz5WXl+e2LDc31+19w4YNSwSxkJAQbd682fU+IyNDLVq0UI0aZX+t7dq1S7m5uapfv36py0/fuFWaH3/8UZLUokWLEstatWqlpUuX6tixY6pdu3aZ2yirps2bN5eY+1xaTf/+97/17LPPatOmTSooKHC1/35sMjIy5OPjU2pgO9MVV1xRoi0kJKTc84d/79dff1VqaqpmzZqlffv2uc1zPfPzLG3fpwNnVFRUifbS6mnevHmJtiuvvFLvv/++pP/7vErr16JFixIhtTxjW1FnHuPpYHuu8f3xxx8VGxtbor20c0+SmjVrVqLOK6+8UtJv83fDw8PLXTNgI8IsYJmgoCA1aNDALciVZvPmzYqMjFRgYKB+/fXXStt/Wf+4n3nj1mmlzfPLyclR9+7dFRgYqPHjx6tp06by9/fXhg0b9MQTT5S40cXX17fUbZsybgwqS3FxserXr69//vOfpS4vK1BWpeLiYvXo0UOPP/54qctPh5Ivv/xSt9xyi7p166bXXntNDRo0UM2aNTVr1iy9++67Hu27ssZV+m0O7KxZszRy5EjFxcUpKChIDodDAwYMKPXGpbL2XVq7J/VURFWMrVS54wugbIRZwEI333yzZsyYoVWrVum6664rsfzLL7/Unj17NGzYMEm/hbTAwMBS7/b+vaZNm56zz+mrSzk5OW7tp6+ElceKFSt06NAhLVy4UN26dXO17969u9zbOFPTpk21du1anTx5ssyba5o2barPPvtM1157bZk305Tl9I8e/Oc//ymxbOfOnQoNDa3wVdnTNR09elTx8fFn7bdgwQL5+/tr6dKlcjqdrvZZs2aV2F5xcbG2b9+umJiYCtfjqfnz5yspKUkvvPCCq+3EiRMlzpPKsmvXrhJt3333neupAqc/r9L6nfkZlndsq0ujRo3KVfdp33//vYwxbv9H87vvvpOkavllMsDbmDMLWOixxx5TQECAhg0bpkOHDrktO3z4sO6//37VqlVLjz32mCTJx8dH/fr107/+9S998803JbZ3+krRbbfdpm+//bbUxxed7nP6qQC/n8tZVFSkN954o9z1n75i9fsrVIWFhXrttdfKvY0z3XbbbcrOztarr75aYtnp/dx5550qKirShAkTSvQ5derUWYNXgwYNFBMTo7feesut39atW/Xpp5/qpptu8qjuO++8U+np6Vq6dGmJZTk5OTp16pSk38bM4XC4XQHfs2ePFi1a5LZOv3795OPjo/Hjx5e4IlqVVwR9fX1LbP+VV14p84r9+Vq0aJH27dvner9u3TqtXbvW9XSL339ev5/msGzZMm3fvr1E7eUZ2+py00036auvvtK6detcbQcPHizzvyj88ssvbn9n8/Ly9PbbbysmJoYpBrgkcGUWsFDz5s311ltvadCgQWrXrl2JXwDLzs7We++95wqekjRx4kR9+umn6t69u+677z61atVK+/fv17x587Rq1SoFBwfrscce0/z583XHHXfo7rvvVseOHXX48GF99NFHmj59utq3b682bdrommuu0ejRo3X48GHVrVtXc+bMcYWu8ujSpYtCQkKUlJSkESNGyOFw6J133jmvsJWYmKi3335bycnJWrdunbp27apjx47ps88+09/+9jfdeuut6t69u4YNG6bU1FRt2rRJPXv2VM2aNbVr1y7NmzdP//jHP3T77beXuY/Jkyerd+/eiouL09ChQ12P5goKCtLYsWM9qvuxxx7TRx99pJtvvtn1WKxjx45py5Ytmj9/vvbs2aPQ0FD16dNHL774onr16qW//OUvOnDggKZNm6ZmzZq5TTlp1qyZnnrqKU2YMEFdu3bVn//8ZzmdTn399deKiIhQamqqR3Wey80336x33nlHQUFBat26tdLT0/XZZ5/p8ssvr5L9NWvWTNddd50eeOABFRQUaOrUqbr88svdpmukpqaqT58+uu6663T33Xfr8OHDeuWVV9SmTRsdPXrU1a+8Y1tdHn/8cb3zzjvq1auXHn74YdejuRo1alRqPVdeeaWGDh2qr7/+WmFhYZo5c6aysrK8dmUZqHbeeIQCgMqxefNmM3DgQNOgQQNTs2ZNEx4ebgYOHGi2bNlSav8ff/zRJCYmmnr16hmn02maNGlihg8fbgoKClx9Dh06ZB588EETGRlp/Pz8TMOGDU1SUpLJzs529cnIyDDx8fHG6XSasLAw8+STT5ply5aV+miuNm3alFrL6tWrzTXXXGMC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STHt27evvMIuEVyZvYilp6crODhYnTp1crXFx8fLx8dHa9euLfd2cnNzFRgYqBo13H9jY/jw4QoNDVXnzp01c+ZMGYsfWVxYWKj169crPj7e1ebj46P4+Hilp6eXuk56erpbf0lKSEhw9d+9e7cyMzPd+gQFBSk2NrbMbdrIk7E70/Hjx3Xy5EnVrVvXrX3FihWqX7++WrRooQceeECHDh2q1NovBJ6O39GjR9WoUSNFRUXp1ltv1bZt21zLOPfKf+69+eabGjBggGrXru3WfimcexV1ru+8yvg8LiXFxcXKz88v8b23a9cuRUREqEmTJho0aJD27t3rpQrtQZi9iGVmZqp+/fpubTVq1FDdunWVmZlZrm1kZ2drwoQJJaYmjB8/Xu+//76WLVum2267TX/729/0yiuvVFrt1S07O1tFRUWuX547LSwsrMyxyszMPGv/0/9bkW3ayJOxO9MTTzyhiIgIt38Ee/XqpbfffltpaWl67rnn9MUXX6h3794qKiqq1Pq9zZPxa9GihWbOnKkPP/xQ//u//6vi4mJ16dJFP//8syTOvfIe57p167R161bdc889bu2XyrlXUWV95+Xl5enXX3+tlO+CS8mUKVN09OhR3Xnnna622NhY1/S+119/Xbt371bXrl2Vn5/vxUovfF7/OVtU3KhRo/Tcc8+dtc+OHTvOez95eXnq06ePWrdurbFjx7ote+aZZ1x/7tChg44dO6bJkydrxIgR571fXFomTZqkOXPmaMWKFW43MQ0YMMD153bt2umqq65S06ZNtWLFCv3xj3/0RqkXjLi4OMXFxbned+nSRa1atdJ///d/a8KECV6szC5vvvmm2rVrp86dO7u1c+6hqr377rsaN26cPvzwQ7eLTr1793b9+aqrrlJsbKwaNWqk999/v9R7V/Abrsxa6O9//7t27Nhx1leTJk0UHh5eYtL9qVOndPjwYYWHh591H/n5+erVq5cuu+wyffDBB6pZs+ZZ+8fGxurnn39WQUHBeR+fN4SGhsrX11dZWVlu7VlZWWWOVXh4+Fn7n/7fimzTRp6M3WlTpkzRpEmT9Omnn+qqq646a98mTZooNDRU33///XnXfCE5n/E7rWbNmurQoYNrbDj3zn2cx44d05w5c8oVEC7Wc6+iyvrOCwwMVEBAQKWcy5eCOXPm6J577tH7779fYtrGmYKD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",
"text/plain": [
"<Figure size 800x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from collections import Counter\n",
"# Count occurrences of each number\n",
"count = Counter([l.lambda_value for l in db.data.values()])\n",
"\n",
"# Separate the counts into two lists for plotting\n",
"x = list(count.keys()) # List of unique numbers\n",
"y = list(count.values()) # List of their respective counts\n",
"\n",
"# Plot the data\n",
"plt.figure(figsize=(8, 6))\n",
"plt.bar(x, y, color='skyblue')\n",
"\n",
"# Adding labels and title\n",
"plt.xlabel('Number')\n",
"plt.ylabel('Occurrences')\n",
"plt.title('Occurance of each lambda in db')\n",
"plt.savefig(f\"{TEMP_BASE_DIR}/lambda_distribution.pdf\")\n",
"\n",
"# Show the plot\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "c192564b-d3c6-40e1-a614-f7a5ee787c4e",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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Li4iODhYxMXFiTlz5ojMzEwhhBBms1n885//FH369BGNGjUSWq1WBAUFie7du4svv/yywo0w7uRr9Ge5ublizpw5IjY2Vvj4+AiNRiP8/PzEAw88IBYuXFhhf+Byy5cvF507dxbu7u6274vly5dXef5r166JiRMniqCgIOHq6iratm0rVq1adct9dm/Wv/DwcBEeHl5hrKysTEyZMkU0btxYaDSaKr+Pieg6SYg//U2IiIiIiEghuGaXiIiIiBSLYZeIiIiIFIthl4iIiIgUi2GXiIiIiBSLYZeIiIiIFIthl4iIiIgUizeVqIIsy7h06RIaNGgASZKcXQ4RERER/YkQAoWFhQgNDbXdabEqDLtVuHTpEsLCwpxdBhERERHdxvnz59GoUaObHmfYrUKDBg0AXP/ieXl52fUcWZaRk5ODgICAW/52QXcH9lNZ2E/lYC+Vhf1UDmf00mg0IiwszJbbboZhtwrlSxe8vLyqFXZLS0vh5eXFH1gFYD+Vhf1UDvZSWdhP5XBmL2+35JTfWURERESkWAy7RERERKRYDLtEREREpFgMu0RERESkWAy7RERERKRYDLtEREREpFgMu0RERESkWAy7RERERKRYDLtEREREpFgMu0RERESkWAy7RERERKRYDLtEREREpFgMu0RERESkWAy7REREROQwWZZx7Ngx2z9Zlp1dUgX1KuxGRERAkqRK/xITEwEApaWlSExMhJ+fHzw9PTFo0CBkZWVVOEdmZib69+8Pd3d3BAYGYvLkybBYLM54O0RERESKlpKSgqHPj8DICa/i45VfYeSEVzH0+RFISUlxdmk29Srs7t+/H5cvX7b927JlCwDgb3/7GwDg5ZdfxoYNG/DNN99g586duHTpEh5//HHb861WK/r37w+z2YyUlBSsXLkSK1aswPTp053yfoiIiIiUKiUlBVOmzcbJIh0i+o5Ck95DENF3FNKKdZgybXa9Cbz1KuwGBAQgODjY9i85ORlNmzbF/fffj4KCAixbtgz//ve/0bNnT3Ts2BFJSUlISUnBnj17AACbN2/G8ePH8cUXX6B9+/bo168f5syZg0WLFsFsNjv53REREREpgyzLWLRkKUr0EWg3YAT0IY2h1rhAH9IYbR8egVLvCCz++JN6saRB4+wCbsZsNuOLL77ApEmTIEkSDh48iLKyMvTu3ds2p2XLlmjcuDF2796N2NhY7N69G23atEFQUJBtTkJCAsaOHYvU1FR06NChytcymUwwmUy2x0ajEcD1RtrbJFmWIYSoF02lO8d+Kgv7qRzspbKwn3evY8eO4Y+MS2jSdxRUEiBBABCQIKCSJER06oW0jZ/g2LFjaN26da3UYO/3Tb0Nu+vXr0d+fj6ef/55AIDBYIBWq4W3t3eFeUFBQTAYDLY5Nwbd8uPlx25m/vz5mDVrVqXxnJwclJaW2lWvLMsoKCiAEAIqVb26YE4OYD+Vhf1UDvZSWdjPu1d2djYiGoehSagv1BoTJAjo1WWQcD3y+oX4QmochuzsbGRnZ9dKDYWFhXbNq7dhd9myZejXrx9CQ0Nr/bWmTp2KSZMm2R4bjUaEhYUhICAAXl5edp1DlmVIkoSAgAD+wCoA+6ks7KdysJfKwn7evQIDA5GeeR64dBX6kMaQICAA5JS5QkBC/mUDMjLPIzAwEIGBgbVSg06ns2tevQy7GRkZ2Lp1K9auXWsbCw4OhtlsRn5+foWru1lZWQgODrbN2bdvX4Vzle/WUD6nKq6urnB1da00rlKpqvXDJ0lStZ9D9Rf7qSzsp3Kwl8rCft6dWrdujRbhoUg7sBVtHx4BlSTh+mIGCbIA0g9sQ8uIhmjdunWt9dbe89bL76ykpCQEBgaif//+trGOHTvCxcUF27Zts42lpaUhMzMTcXFxAIC4uDgcPXq0wuXyLVu2wMvLC9HR0XX3BoiIiIgUTKVSIXHMKOjy03EkeTnyL2fAWmZG/uUMHEleDl1+OsaNfqFe/BJT767syrKMpKQkDBs2DBrN/8rT6/UYOXIkJk2aBF9fX3h5eWHChAmIi4tDbGwsAKBPnz6Ijo7G0KFDsWDBAhgMBrz55ptITEys8sotERERETkmPj4eC+ZMx6IlS/HHxk8gNQ5DRuZ5tIxoiHGvTEd8fLyzSwRQD8Pu1q1bkZmZiREjRlQ69u6770KlUmHQoEEwmUxISEjA4sWLbcfVajWSk5MxduxYxMXFwcPDA8OGDcPs2bPr8i0QERER/SXEx8cjNjYWx44dQ3Z2NgIDA2t16YIjJCGEcHYR9Y3RaIRer0dBQUG1PqBW3uT61GByDPupLOyncrCXysJ+KoczemlvXuN3FhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESkWwy4RERERKRbDLhEREREpFsMuERERESlWvQu7Fy9exLPPPgs/Pz+4ubmhTZs2OHDggO24EALTp09HSEgI3Nzc0Lt3b5w6darCOa5evYohQ4bAy8sL3t7eGDlyJIqKiur6rRARERGRk9WrsJuXl4d7770XLi4u+PHHH3H8+HH861//go+Pj23OggULsHDhQixZsgR79+6Fh4cHEhISUFpaapszZMgQpKamYsuWLUhOTsauXbswatQoZ7wlIiIiInIijbMLuNE///lPhIWFISkpyTYWGRlp+28hBN577z28+eabePTRRwEAn332GYKCgrB+/XoMHjwYJ06cwMaNG7F//3506tQJAPDBBx/goYcewjvvvIPQ0NC6fVNERERE5DT1Kux+//33SEhIwN/+9jfs3LkTDRs2xLhx4/DCCy8AAM6dOweDwYDevXvbnqPX69G1a1fs3r0bgwcPxu7du+Ht7W0LugDQu3dvqFQq7N27FwMHDqz0uiaTCSaTyfbYaDQCAGRZhizLdtUuyzKEEHbPp/qN/VQW9lM52EtlYT+Vwxm9tPe16lXYPXv2LD766CNMmjQJ//jHP7B//35MnDgRWq0Ww4YNg8FgAAAEBQVVeF5QUJDtmMFgQGBgYIXjGo0Gvr6+tjl/Nn/+fMyaNavSeE5OToXlEbciyzIKCgoghIBKVa9Wh5AD2E9lYT+Vg71UFvZTOZzRy8LCQrvm1auwK8syOnXqhLfeegsA0KFDBxw7dgxLlizBsGHD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",
"text/plain": [
"<Figure size 800x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Plotting lambda against access_count.\n",
"\n",
"plt.figure(figsize=(8, 6))\n",
"plt.scatter(merged['lambda'], merged['access_count'], alpha=0.7, edgecolor='k')\n",
"plt.title('Lambda vs Access Count', fontsize=14)\n",
"plt.xlabel('Lambda', fontsize=12)\n",
"plt.ylabel('Access Count', fontsize=12)\n",
"plt.grid(alpha=0.3)\n",
"\n",
"plt.savefig(f\"{TEMP_BASE_DIR}/lambda_vs_access_count.pdf\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "00a12eea-c805-4209-9143-48fa65619873",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAq4AAAIjCAYAAADC0ZkAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABAQ0lEQVR4nO3deVxV1R738e8BZXAAQQQcSBHNOccsMYdrpLestCzTx3IsrTAzb6Y0aKmJ2mSpZXVzaLp2HRvuVTM1TTMzZ9PMCNNbIqICDjnBev7o4TweBoXjkeOSz/v1Oq+XZ+211/6dxQK+bvbZx2GMMQIAAACucD7eLgAAAAAoDIIrAAAArEBwBQAAgBUIrgAAALACwRUAAABWILgCAADACgRXAAAAWIHgCgAAACsQXAEAAGAFgiuAq9qGDRsUGxursmXLyuFwaMuWLd4uyUWNGjV0++23e7sMtzkcDj3//POX/Tjt27dX+/btnc+//vprORwOzZs375LGnTRpkurWravs7OxLrNA7nn/+eTkcDo+OmXuud+7cqVKlSmnHjh0ePQ7gDoIr4AE//vij7r//flWtWlX+/v6qUqWKevXqpR9//NHbpZVoZ8+e1b333qsjR47otdde0wcffKDq1at7uyxcITIzMzVx4kSNGDFCPj78OixI/fr11blzZ40aNcrbpQAq5e0CANstWLBAPXv2VGhoqAYMGKDo6Gjt3btX7733nubNm6c5c+borrvu8naZJVJSUpJ+++03vfvuu3rwwQe9Xc5V6c8//1SpUnb+KpkxY4bOnTunnj17eruUK97DDz+s2267TUlJSYqJifF2OSjB7PxpA1whkpKS9MADD6hmzZpavXq1KlWq5Nz2+OOPq02bNnrggQe0bds21axZ04uV5nXy5EmVKVPG22VcVqmpqZKkChUqeLeQq1hAQIC3S3DbzJkzdeedd170NZw7d07Z2dny8/MrpsquPHFxcQoJCdHs2bM1ZswYb5eDEoy/jQCX4KWXXtLJkyf1zjvvuIRWSQoLC9Pbb7+tEydOaNKkSS7bfv/9dw0YMEBVqlSRv7+/oqOj9cgjj+jMmTPOPunp6XriiSdUo0YN+fv7q1q1aurdu7fS0tIkSbNmzZLD4dDevXtdxs659u/rr792trVv314NGzbUxo0b1bZtW5UpU0ZPP/20JOnTTz9V586dnbXExMRo7NixysrKchk3Z4ydO3fqb3/7m8qUKaOqVavmeW2SdOrUKT3//PO69tprFRAQoMqVK+vuu+9WUlKSs092drYmT56sBg0aKCAgQBERERo0aJCOHj1aqLlfsWKF2rRpo7Jly6pChQrq0qWLdu3a5dzet29ftWvXTpJ07733yuFwuFy3l5/09HQNHTpUUVFR8vf3V61atTRx4sQ81z++/PLLio2NVcWKFRUYGKjmzZsXeK3lhx9+qJYtW6pMmTIKCQlR27Zt9eWXX+bpt2bNGrVs2VIBAQGqWbOm3n///YvOwd69e+VwOPTyyy9r2rRpqlmzpsqUKaOOHTtq//79MsZo7NixqlatmgIDA9WlSxcdOXLEZYyCrlGtUaOG+vbte9Eacu+fc83lL7/8or59+6pChQoKDg5Wv379dPLkyYuOJ0nvvPOOYmJiFBgYqJYtW+qbb74psG9WVpaefvppRUZGqmzZsrrzzju1f//+ix4jOTlZ27ZtU1xcnEv7+XM6efJkxcTEyN/fXzt37pR08XUn/bX2atSokeeY+V2P6nA4NHjwYC1atEgNGzaUv7+/GjRooCVLluTZf82aNbr++usVEBCgmJgYvf322wW+vg8//FDNmzdXYGCgQkND1aNHj3znpbBzXbp0abVv316ffvppgccEigNnXIFL8Pnnn6tGjRpq06ZNvtvbtm2rGjVq6D//+Y+z7Y8//lDLli2Vnp6ugQMHqm7duvr99981b948nTx5Un5+fjp+/LjatGmjXbt2qX///mrWrJnS0tL02Wef6X//+5/CwsKKXOvhw4d16623qkePHrr//vsVEREh6a8AXK5cOQ0bNkzlypXTihUrNGrUKGVmZuqll15yGePo0aP6+9//rrvvvlvdu3fXvHnzNGLECDVq1Ei33nqrpL+CxO23367ly5erR48eevzxx3Xs2DEtW7ZMO3bscP6ZcdCgQZo1a5b69eunIUOGKDk5WVOnTtXmzZu1du1alS5dusDX8tVXX+nWW29VzZo19fzzz+vPP//UlClT1Lp1a23atEk1atTQoEGDVLVqVY0fP15DhgzR9ddf73zN+Tl58qTatWun33//XYMGDdI111yjb7/9VgkJCTpw4IAmT57s7Pv666/rzjvvVK9evXTmzBnNmTNH9957r7744gt17tzZ2e+FF17Q888/r9jYWI0ZM0Z+fn5av369VqxYoY4dOzr7/fLLL7rnnns0YMAA9enTRzNmzFDfvn3VvHlzNWjQ4KJf248++khnzpzRY489piNHjmjSpEnq3r27OnTooK+//lojRozQL7/8oilTpujJJ5/UjBkzLjrmperevbuio6OVmJioTZs26Z///KfCw8M1ceLEC+733nvvadCgQYqNjdXQoUP166+/6s4771RoaKiioqLy9H/xxRflcDg0YsQIpaamavLkyYqLi9OWLVsUGBhY4HG+/fZbSVKzZs3y3T5z5kydOnVKAwcOlL+/v0JDQwu17tyxZs0aLViwQI8++qjKly+vN954Q926ddO+fftUsWJFSdL27dvVsWNHVapUSc8//7zOnTun0aNH57umX3zxRT333HPq3r27HnzwQR06dEhTpkxR27ZttXnzZudfIIo6182bN9enn36qzMxMBQUFufVagUtmALglPT3dSDJdunS5YL8777zTSDKZmZnGGGN69+5tfHx8zIYNG/L0zc7ONsYYM2rUKCPJLFiwoMA+M2fONJJMcnKyy/aVK1caSWblypXOtnbt2hlJZvr06XnGO3nyZJ62QYMGmTJlyphTp07lGeP99993tp0+fdpERkaabt26OdtmzJhhJJlXX321wNq/+eYbI8l89NFHLtuXLFmSb3tuTZo0MeHh4ebw4cPOtq1btxofHx/Tu3dvZ1vOXMydO/eC4xljzNixY03ZsmXNzz//7NI+cuRI4+vra/bt2+dsyz1nZ86cMQ0bNjQdOnRwtu3Zs8f4+PiYu+66y2RlZbn0z5kHY4ypXr26kWRWr17tbEtNTTX+/v7mH//4xwVrTk5ONpJMpUqVTHp6urM9ISHBSDKNGzc2Z8+edbb37NnT+Pn5uXxdJZnRo0fnGbt69eqmT58+Fzx+fvuPHj3aSDL9+/d36XfXXXeZihUrXnCsM2fOmPDwcNOkSRNz+vRpZ/s777xjJJl27do523K+tlWrVnV+bxljzL///W8jybz++usXPNazzz5rJJljx465tOfMaVBQkElNTXXZVth116dPH1O9evU8x8yZm/NJMn5+fuaXX35xGVOSmTJlirOta9euJiAgwPz222/Otp07dxpfX1+XMffu3Wt8fX3Niy++6HKc7du3m1KlSjnbizLXOT7++GMjyaxfvz7PNqC4cKkA4KZjx45JksqXL3/Bfjnb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/fffS/rrbOvkyZP17LPPqkuXLpKk999/XxEREVq0aJF69OjhtdoBAABQvLx6xjU2NlbLly/Xzz//LEnaunWr1qxZo1tvvVWSlJycrJSUFMXFxTn3CQ4O1g033KB169blO+bp06eVmZnp8gAAAID9vHrGdeTIkcrMzFTdunXl6+urrKwsvfjii+rVq5ckKSUlRZIUERHhsl9ERIRzW26JiYl64YUXLm/hAAAAKHZePeP673//Wx999JE+/vhjbdq0SbNnz9bLL7+s2bNnuz1mQkKCMjIynI/9+/d7sGIAAAB4i1fPuA4fPlwjR450XqvaqFEj/fbbb0pMTFSfPn0UGRkpSTp48KAqV67s3O/gwYNq0qRJvmP6+/vL39//stcOAACA4uXVM64nT56Uj49rCb6+vsrOzpYkRUdHKzIyUsuXL3duz8zM1Pr169WqVatirRUAAADe5dUzrnfccYdefPFFXXPNNWrQoIE2b96sV199Vf3795ckORwODR06VOPGjVPt2rUVHR2t5557TlWqVFHXrl29WToAAACKmVeD65QpU/Tcc8/p0UcfVWpqqqpUqaJBgwZp1KhRzj5PPfWUTpw4oYEDByo9PV033XSTlixZooCAAC9WDgAAgOLmMOd/TNVVKDMzU8HBwcrIyFBQUFCxHHPC5rRiOQ6K38imYd4uAQCAq05h85pXr3EFAAAACovgCgAAACsQXAEAAGAFgisAAACsQHAFAACAFQiuAAAAsALBFQAAAFYguAIAAMAKBFcAAABYgeAKAAAAKxBcAQAAYAWCKwAAAKxAcAUAAIAVCK4AAACwAsEVAAAAViC4AgAAwAoEVwAAAFiB4AoAAAArEFwBAABgBYIrAAAArEBwBQAAgBUIrgAAALACwRUAAABWILgCAADACgRXAAAAWIHgCgAAACsQXAEAAGAFgisAAACsQHAFAACAFQiuAAAAsALBFQAAAFYguAIAAMAKBFcAAABYgeAKAAAAKxBcAQAAYAWCKwAAAKxAcAUAAIAVCK4AAACwAsEVAAAAViC4AgAAwAoEVwAAAFiB4AoAAAArEFwBAABgBYIrAAAArEBwBQAAgBUIrgAAALACwRUAAABWILgCAADACgRXAAAAWIHgCgAAACsQXAEAAGAFgisAAACsQHAFAACAFQiuAAAAsALBFQAAAFYguAIAAMAKBFcAAABYgeAKAAAAKxBcAQAAYAWCKwAAAKxAcAUAAIAVCK4AAACwAsEVAAAAViC4AgAAwAoEVwAAAFiB4AoAAAArEFwBAABgBYIrAAAArEBwBQAAgBUIrgAAALACwRUAAABWILgCAADACgRXAAAAWIHgCgAAACsQXAEAAGAFgisAAACsQHAFAACAFQiuAAAAsALBFQAAAFYguAIAAMAKBFcAAABYgeAKAAAAKxBcAQAAYAWCKwAAAKxAcAUAAIAVCK4AAACwgteD6++//677779fFStWVGBgoBo1aqQffvjBud0Yo1GjRqly5coKDAxUXFyc9uzZ48WKAQAA4A1eDa5Hjx5V69atVbp0aS1evFg7d+7UK6+8opCQEGefSZMm6Y033tD06dO1fv16lS1bVp06ddKpU6e8WDkAAACKWylvHnzixImKiorSzJkznW3R0dHOfxtjNHnyZD377LPq0qWLJOn9999XRESEFi1apB49ehR7zQAAAPAOr55x/eyzz9SiRQvde++9Cg8PV9OmTfXuu+86tycnJyslJUVxcXHOtuDgYN1www1at25dvmOePn1amZmZLg8AAADYz6vB9ddff9Vbb72l2rVra+nSpXrkkUc0ZMgQzZ49W5KUkpIiSYqIiHDZLyIiwrktt8TERAUHBzsfUVFRl/dFAAAAoFh4NbhmZ2erWbNmGj9+vJo2baqBAwfqoYce0vTp090eMyEhQRkZGc7H/v37PVgxAAAAvMWrwbVy5cqqX7++S1u9evW0b98+SVJkZKQk6eDBgy59Dh486NyWm7+/v4KCglweAAAAsJ9Xg2vr1q21e/dul7aff/5Z1atXl/TXG7UiIyO1fPly5/bMzEytX79erVq1KtZaAQAA4F1evavAE088odjYWI0fP17du3fX999/r3feeUfvvPOOJMnhcGjo0KEaN26cateurejoaD333HOqUqWKunbt6s3SAQAAUMy8Glyvv/56LVy4UAkJCRozZoyio6M1efJk9erVy9nnqaee0okTJzRw4EClp6frpptu0pIlSxQQEODFygEAAFDcHMYY4+0iLqfMzEwFBwcrIyOj2K53nbA5rViOg+I3smmYt0sAAOCqU9i85vWPfAUAAAAKg+AKAAAAKxBcAQAAYAWCKwAAAKxAcAUAAIAVCK4AAACwAsEVAAAAViC4AgAAwAoEVwAAAFiB4AoA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/fr16tu376XWBAAAAOThVnDdvHmzWrdunaf9xhtv1JYtWy61JgAAACAPt4Krw+HQsWPH8rRnZGQoKyvrkosCAAAAcnMruLZt21aJiYkuITUrK0uJiYm66aabPFYcAAAAkMOtuwpMnDhRbdu2VZ06ddSmTRtJ0jfffKPMzEytWLHCowUCAAAAkptnXOvXr69t27ape/fuSk1N1bFjx9S7d2/99NNPatiwoadrBAAAANw74ypJVapU0fjx4z1ZCwAAAFAgt864zpw5U3Pnzs3TPnfuXM2ePfuSiwIAAABycyu4JiYmKiwsLE97eHg4Z2EBAABwWbgVXPft26fo6Og87dWrV9e+ffsuuSgAAAAgN7eCa3h4uLZt25anfevWrapYsaJbhUyYMEEOh0NDhw51tp06dUrx8fGqWLGiypUrp27duungwYNujQ8AAAC7uRVce/bsqSFDhmjlypXKyspSVlaWVqxYoccff1w9evQo8ngbNmzQ22+/reuuu86l/YknntDnn3+uuXPnatWqVfrjjz909913u1MyAAAALOfWXQXGjh2rvXv36uabb1apUn8NkZWVpT59+hT5Gtfjx4+rV69eevfddzVu3Dhne0ZGht577z19/PHH6tChg6S/3hRWr149fffdd7rxxhvdKR0AAACWcuuMq5+fnz755BOtX79eH330kRYsWKBff/1VM2bMkJ+fX5HGio+PV+fOnRUXF+fSvnHjRp09e9alvW7durrmmmu0bt26Asc7ffq0MjMzXR4AAACwX5HPuKanp+uZZ57RJ598oqNHj0qSQkJC1KNHD40bN04VKlQo9Fhz5szRpk2btGHDhjzbUlJS5Ofnl2e8iIgIpaSkFDhmYmKiXnjhhULXAAAAADsUKbgeOXJErVq10u+//65evXqpXr16kqSdO3dq1qxZWr58ub799luFhIRcdKz9+/fr8ccf17JlyxQQEOBe9flISEjQsGHDnM8zMzMVFRXlsfEBAADgHUUKrmPGjJGfn5+SkpIUERGRZ1vHjh01ZswYvfbaaxcda+PGjUpNTVWzZs2cbVlZWVq9erWmTp2qpUuX6syZM0pPT3c563rw4EFFRkYWOK6/v7/8/f2L8rIAAABggSJd47po0SK9/PLLeUKrJEVGRmrSpElauHBhoca6+eabtX37dm3ZssX5aNGihXr16uX8d+nSpbV8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",
"text/plain": [
"<Figure size 800x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from collections import Counter\n",
"# Count occurrences of each number\n",
"count = Counter(np.array([l.mu_value if l.mu_value is not None else 0.0 for l in db.data.values() ]).round(0))\n",
"\n",
"# Separate the counts into two lists for plotting\n",
"x = list(count.keys()) # List of unique numbers\n",
"y = list(count.values()) # List of their respective counts\n",
"\n",
"# Plot the data\n",
"plt.figure(figsize=(8, 6))\n",
"plt.bar(x, y, color='skyblue')\n",
"\n",
"# Adding labels and title\n",
"plt.xlabel('Number')\n",
"plt.ylabel('Occurrences')\n",
"plt.title('Occurance of each mu in db (rounded)')\n",
"\n",
"# Show the plot\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "adbfeb40-76bd-4224-ac45-65c7b2b2cb7b",
"metadata": {},
"outputs": [],
"source": [
"def plot_requests(object_id: int):\n",
" mu = db.mu_values[object_id]\n",
" lmb = db.lambda_values[object_id]\n",
" rq_log = np.array(cache.request_log[object_id])\n",
" df = rq_log[1:] - rq_log[:-1]\n",
" pd.DataFrame(df, columns=[f\"{object_id}, mu:{mu:.2f}, lambda: {lmb:.2f}\"]).plot()"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "1f550686-3463-4e50-be83-ceafb27512b0",
"metadata": {},
"outputs": [],
"source": [
"def print_rate(object_id: int):\n",
" # Calculate time intervals between consecutive events\n",
" intervals = np.diff(np.array(cache.request_log[object_id])) # Differences between each event time\n",
" \n",
" # Calculate the rate per second for each interval\n",
" rates = 1 / intervals # Inverse of the time interval gives rate per second\n",
" \n",
" # Optional: Calculate the average event rate over all intervals\n",
" average_rate = np.mean(rates)\n",
" print(\"Average event rate per second:\", average_rate)\n",
" print(\"The mu is: \", db.lambda_values[object_id])"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "5b6dac2e-8596-4e7c-97d8-aaf9632e4154",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"count 90.000000\n",
"mean 0.050767\n",
"std 0.027965\n",
"min 0.025100\n",
"25% 0.030700\n",
"50% 0.040200\n",
"75% 0.060625\n",
"max 0.146900\n",
"Name: lambda, dtype: float64"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"merged[merged['hits']==0]['lambda'].describe()"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "29393374-e379-42c8-8333-abfecc18e828",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"count 10.000000\n",
"mean 0.356500\n",
"std 0.259982\n",
"min 0.158500\n",
"25% 0.194825\n",
"50% 0.257200\n",
"75% 0.393875\n",
"max 1.000000\n",
"Name: lambda, dtype: float64"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"merged[merged['hits']>0]['lambda'].describe()"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "b47990b1-0231-43ac-8bc5-8340abe4a8b3",
"metadata": {},
"outputs": [],
"source": [
"# os.makedirs(EXPERIMENT_BASE_DIR, exist_ok=True)\n",
"# folder_name = experiment_name.replace(\" \", \"_\").replace(\"(\", \"\").replace(\")\", \"\").replace(\".\", \"_\")\n",
"# folder_path = os.path.join(EXPERIMENT_BASE_DIR, folder_name)\n",
"# os.makedirs(folder_path, exist_ok=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "db83cad4-7cc6-4702-ae3a-d1af30a561d2",
"metadata": {},
"outputs": [],
"source": [
"# file_names = os.listdir(TEMP_BASE_DIR)\n",
" \n",
"# for file_name in file_names:\n",
"# shutil.move(os.path.join(TEMP_BASE_DIR, file_name), folder_path)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "graphs",
"language": "python",
"name": "graphs"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}