From e5934d9948a7ad391b7b08132f218a605b9db5c8 Mon Sep 17 00:00:00 2001 From: Andreas Tsouchlos Date: Wed, 23 Nov 2022 12:55:35 +0100 Subject: [PATCH] Simulation name now also being saved as metadata --- sw/main.py | 84 ++++++++++++---------- sw/plot_results.py | 48 ++++++++----- sw/sim_results/2043486_metadata.json | 1 + sw/sim_results/20455187_metadata.json | 1 + sw/sim_results/40833844_metadata.json | 1 + sw/sim_results/8161a4845_metadata.json | 1 + sw/sim_results/963965_metadata.json | 1 + sw/sim_results/99911135543_metadata.json | 1 + sw/sim_results/99911135565_metadata.json | 1 + sw/sim_results/pegreg252x504_metadata.json | 1 + sw/utility/simulation.py | 79 ++++++++++++-------- 11 files changed, 133 insertions(+), 86 deletions(-) diff --git a/sw/main.py b/sw/main.py index 5aa2187..14ec9c7 100644 --- a/sw/main.py +++ b/sw/main.py @@ -1,53 +1,63 @@ import numpy as np -from pathlib import Path from decoders import proximal, maximum_likelihood from utility import simulation, codes -def main(): - Path("sim_results").mkdir(parents=True, exist_ok=True) - +def start_new_simulation(sim_mgr: simulation.SimulationManager): sim_name = "test" - sim_mgr = simulation.SimulationManager(results_dir="sim_results", - save_dir="sim_saves") + # H = codes.read_alist_file("res/204.3.486.alist") + # H = codes.read_alist_file("res/204.55.187.alist") + H = codes.read_alist_file("res/96.3.965.alist") + # H = codes.read_alist_file("res/408.33.844.alist") + # H = codes.read_alist_file("res/PEGReg252x504.alist") + # H = codes.read_alist_file("res/999.111.3.5543.alist") + # H = codes.read_alist_file("res/999.111.3.5565.alist") + # H = codes.read_alist_file("res/816.1A4.845.alist") + k, n = H.shape - if sim_mgr.unfinished_simulation_present(sim_name): + decoders = [ + proximal.ProximalDecoder(H, gamma=0.01), + proximal.ProximalDecoder(H, gamma=0.05), + proximal.ProximalDecoder(H, gamma=0.15) + ] + + labels = [ + "proximal $\\gamma = 0.01$", + "proximal $\\gamma = 0.05$", + "proximal $\\gamma = 0.15$" + ] + + sim = simulation.Simulator(n=n, k=k, decoders=decoders, + target_frame_errors=100, + SNRs=np.arange(1, 6, 0.5)) + + sim_mgr.configure_simulation(simulator=sim, name=sim_name, + column_labels=labels) + sim_mgr.simulate() + + +def main(): + # Perform necessary initialization + + results_dir = "sim_results" + saves_dir = "sim_saves" + + sim_mgr = simulation.SimulationManager(results_dir=results_dir, + saves_dir=saves_dir) + + # Calculate BERs + + unfinished_sims = sim_mgr.get_unfinished() + + if len(unfinished_sims) > 0: print("Found unfinished simulation. Picking up where it was left of") - sim_mgr.load_unfinished(sim_name=sim_name) + sim_mgr.load_unfinished(unfinished_sims[0]) sim_mgr.simulate() else: - # H = codes.read_alist_file("res/204.3.486.alist") - # H = codes.read_alist_file("res/204.55.187.alist") - # H = codes.read_alist_file("res/96.3.965.alist") - # H = codes.read_alist_file("res/408.33.844.alist") - # H = codes.read_alist_file("res/PEGReg252x504.alist") - # H = codes.read_alist_file("res/999.111.3.5543.alist") - # H = codes.read_alist_file("res/999.111.3.5565.alist") - H = codes.read_alist_file("res/816.1A4.845.alist") - k, n = H.shape - - decoders = [ - proximal.ProximalDecoder(H, gamma=0.01), - proximal.ProximalDecoder(H, gamma=0.05), - proximal.ProximalDecoder(H, gamma=0.15) - ] - - labels = [ - "proximal $\\gamma = 0.01$", - "proximal $\\gamma = 0.05$", - "proximal $\\gamma = 0.15$" - ] - - sim = simulation.Simulator(n=n, k=k, decoders=decoders, - target_frame_errors=3, - SNRs=np.arange(1, 6, 0.5)) - - sim_mgr.configure_simulation(simulator=sim, name=sim_name, - column_labels=labels) - sim_mgr.simulate() + start_new_simulation(sim_mgr) if __name__ == "__main__": diff --git a/sw/plot_results.py b/sw/plot_results.py index 2920028..a894aef 100644 --- a/sw/plot_results.py +++ b/sw/plot_results.py @@ -1,37 +1,49 @@ -import numpy as np +import typing + import matplotlib.pyplot as plt import seaborn as sns -import pandas as pd import os from utility import visualization, simulation -def plot_results(): - sim_names = [ - "96.3965", - "204.3.486", - "204.55.187", - "408.33.844", - "816.1A4.845", - "999.111.3.5543", - "999.111.3.5565", - "PEGReg252x504" - ] +# TODO: This should be the responsibility of the DeSerializer +def get_sim_slugs(results_dir: str) -> typing.List[str]: + """Get a list of slugified simulation names.""" + result_files = [f for f in os.listdir(results_dir) if + os.path.isfile(os.path.join(results_dir, f))] - deserializer = simulation.SimulationDeSerializer(save_dir="sim_saves", - results_dir="sim_results") + metadata_files = [f for f in result_files if f.endswith("_metadata.json")] + + sim_slugs = [f.removesuffix("_metadata.json") for f in metadata_files] + + return sim_slugs + + +def plot_results() -> None: + """Plot the BER curves for all present simulation results.""" + saves_dir = "sim_saves" + results_dir = "sim_results" + + slugs = get_sim_slugs(results_dir) + + deserializer = simulation.SimulationDeSerializer(save_dir=saves_dir, + results_dir=results_dir) + + # Read data data = [] - for sim_name in sim_names: - df, metadata = deserializer.read_results(sim_name) + for slug in slugs: + df, metadata = deserializer.read_results(slug) df = df.loc[:, ~df.columns.str.contains('^Unnamed')] - graph_title = sim_name + graph_title = metadata["name"] line_labels = metadata["labels"] graph_tuple = (graph_title, df, line_labels) data.append(graph_tuple) + # Plot results + sns.set_theme() fig = visualization.plot_BERs( title="Bit-Error-Rates of proximal decoder for different codes", diff --git a/sw/sim_results/2043486_metadata.json b/sw/sim_results/2043486_metadata.json index ff9f5b2..551e85a 100644 --- a/sw/sim_results/2043486_metadata.json +++ b/sw/sim_results/2043486_metadata.json @@ -1,4 +1,5 @@ { + "name": "204.3.486", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/sim_results/20455187_metadata.json b/sw/sim_results/20455187_metadata.json index ff9f5b2..c715048 100644 --- a/sw/sim_results/20455187_metadata.json +++ b/sw/sim_results/20455187_metadata.json @@ -1,4 +1,5 @@ { + "name": "204.55.187", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/sim_results/40833844_metadata.json b/sw/sim_results/40833844_metadata.json index ff9f5b2..ff4c018 100644 --- a/sw/sim_results/40833844_metadata.json +++ b/sw/sim_results/40833844_metadata.json @@ -1,4 +1,5 @@ { + "name": "408.33.844", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/sim_results/8161a4845_metadata.json b/sw/sim_results/8161a4845_metadata.json index ff9f5b2..7af4536 100644 --- a/sw/sim_results/8161a4845_metadata.json +++ b/sw/sim_results/8161a4845_metadata.json @@ -1,4 +1,5 @@ { + "name": "816.1A4.845", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/sim_results/963965_metadata.json b/sw/sim_results/963965_metadata.json index ff9f5b2..c3a50ea 100644 --- a/sw/sim_results/963965_metadata.json +++ b/sw/sim_results/963965_metadata.json @@ -1,4 +1,5 @@ { + "name":"96.3965", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/sim_results/99911135543_metadata.json b/sw/sim_results/99911135543_metadata.json index ff9f5b2..eb6cc77 100644 --- a/sw/sim_results/99911135543_metadata.json +++ b/sw/sim_results/99911135543_metadata.json @@ -1,4 +1,5 @@ { + "name": "999.111.3.5543", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/sim_results/99911135565_metadata.json b/sw/sim_results/99911135565_metadata.json index ff9f5b2..089e6b3 100644 --- a/sw/sim_results/99911135565_metadata.json +++ b/sw/sim_results/99911135565_metadata.json @@ -1,4 +1,5 @@ { + "name": "999.111.3.5565", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/sim_results/pegreg252x504_metadata.json b/sw/sim_results/pegreg252x504_metadata.json index ff9f5b2..8f70c7f 100644 --- a/sw/sim_results/pegreg252x504_metadata.json +++ b/sw/sim_results/pegreg252x504_metadata.json @@ -1,4 +1,5 @@ { + "name": "PEGReg252x504", "labels": [ "proximal $\\gamma = 0.01$", "proximal $\\gamma = 0.05$", diff --git a/sw/utility/simulation.py b/sw/utility/simulation.py index a918483..57f13e0 100644 --- a/sw/utility/simulation.py +++ b/sw/utility/simulation.py @@ -7,7 +7,7 @@ import typing from tqdm import tqdm import signal import pickle -import os.path +import os from pathlib import Path from utility import noise, misc @@ -249,14 +249,14 @@ class SimulationDeSerializer: Simulator objects.""" def __init__(self, save_dir: str, results_dir: str): - self._save_dir = save_dir + self._saves_dir = save_dir self._results_dir = results_dir - Path(self._save_dir).mkdir(parents=True, exist_ok=True) + Path(self._saves_dir).mkdir(parents=True, exist_ok=True) Path(self._results_dir).mkdir(parents=True, exist_ok=True) def _get_savefile_path(self, sim_name): - return f"{self._save_dir}/{misc.slugify(sim_name)}_sim_state.pickle" + return f"{self._saves_dir}/{misc.slugify(sim_name)}_state.pickle" def _get_metadata_path(self, sim_name): return f"{self._results_dir}/{misc.slugify(sim_name)}_metadata.json" @@ -264,16 +264,41 @@ class SimulationDeSerializer: def _get_results_path(self, sim_name): return f"{self._results_dir}/{misc.slugify(sim_name)}.csv" - # TODO: Should this function also check for the metadata file? - # Currently, if the state-savefile is present, but not the metadata, - # this function will return true but loading the saved state will fail - def unfinished_sim_present(self, sim_name: str): - """Check if the savefile of a previously paused simulation is present. + def _read_metadata(self, sim_name) -> typing.Dict: + with open(self._get_metadata_path(sim_name), 'r', + encoding='utf-8') as f: + return json.load(f) - :param sim_name: + def _save_metadata(self, sim_name, metadata) -> None: + with open(self._get_metadata_path(sim_name), 'w+', + encoding='utf-8') as f: + json.dump(metadata, f, ensure_ascii=False, indent=4) + + def unfinished_sim_present(self, sim_name: str): + """Check if the savefile of a previously paused simulation is + present. + + :param sim_name: Name :return: True if a paused simulation with the given name is found """ - return os.path.isfile(self._get_savefile_path(sim_name)) + return os.path.isfile( + self._get_savefile_path(sim_name)) and os.path.isfile( + self._get_metadata_path(sim_name)) + + # TODO: Make the directories configurable in the init function + def get_unfinished_sims(self) -> typing.List[str]: + """Get a list unfinished simulations.""" + result = [] + + save_files = [f for f in os.listdir(self._saves_dir) if + os.path.isfile(os.path.join(self._saves_dir, f))] + + state_files = [f for f in save_files if f.endswith("_state.pickle")] + sim_slugs = [f.removesuffix("_state.pickle") for f in state_files] + + sim_names = [self._read_metadata(slug)["name"] for slug in sim_slugs] + + return sim_names def remove_unfinished_sim(self, sim_name): """Remove the savefile of a previously paused simulation. @@ -292,9 +317,7 @@ class SimulationDeSerializer: :param metadata: Metadata to be saved besides the actual state """ # Save metadata - with open(self._get_metadata_path(sim_name), 'w+', - encoding='utf-8') as f: - json.dump(metadata, f, ensure_ascii=False, indent=4) + self._save_metadata(sim_name, metadata) # Save simulation state with open(self._get_savefile_path(sim_name), "wb") as file: @@ -311,9 +334,7 @@ class SimulationDeSerializer: simulator = None # Read metadata - with open(self._get_metadata_path(sim_name), 'r', - encoding='utf-8') as f: - metadata = json.load(f) + metadata = self._read_metadata(sim_name) # Read simulation state with open(self._get_savefile_path(sim_name), "rb") as file: @@ -332,9 +353,7 @@ class SimulationDeSerializer: results """ # Save metadata - with open(self._get_metadata_path(sim_name), 'w+', - encoding='utf-8') as f: - json.dump(metadata, f, ensure_ascii=False, indent=4) + self._save_metadata(sim_name, metadata) # Save results df = simulator.get_current_results() @@ -349,9 +368,7 @@ class SimulationDeSerializer: dataframe and metadata is a dict """ # Read metadata - with open(self._get_metadata_path(sim_name), 'r', - encoding='utf-8') as f: - metadata = json.load(f) + metadata = self._read_metadata(sim_name) # Read results results = pd.read_csv(self._get_results_path(sim_name)) @@ -369,15 +386,15 @@ class SimulationManager: All actual work is outsourced to a provided simulator class. """ - def __init__(self, save_dir: str, results_dir: str): + def __init__(self, saves_dir: str, results_dir: str): """Construct a SimulationManager object. - :param save_dir: Directory in which the simulation state of a paused + :param saves_dir: Directory in which the simulation state of a paused simulation should be stored :param results_dir: Directory in which the results of the simulation should be stored """ - self._de_serializer = SimulationDeSerializer(save_dir, results_dir) + self._de_serializer = SimulationDeSerializer(saves_dir, results_dir) self._simulator = None self._sim_name = None @@ -398,19 +415,19 @@ class SimulationManager: """Configure a new simulation.""" self._simulator = simulator self._sim_name = name + self._metadata["name"] = name self._metadata["labels"] = column_labels - def unfinished_simulation_present(self, sim_name: str) -> bool: - """Check whether the savefile of a previously unfinished simulation - is present.""" - return self._de_serializer.unfinished_sim_present(sim_name) + def get_unfinished(self) -> typing.List[str]: + """Get a list of names of all present unfinished simulations.""" + return self._de_serializer.get_unfinished_sims() def load_unfinished(self, sim_name: str) -> None: """Load the state of an unfinished simulation its savefile. Warning: This function deletes the savefile after loading. """ - assert self.unfinished_simulation_present(sim_name) + assert self._de_serializer.unfinished_sim_present(sim_name) self._sim_name = sim_name self._simulator, self._metadata = self._de_serializer.read_state(