Explorar el Código

changed dynamic LI and HI structure so there is only a single generator for the whole mode at max depth which propagates the changes upward via modelTransition. Fixed dot generator for different depths

Snej69420 hace 11 meses
padre
commit
1cbe3563ee
Se han modificado 3 ficheros con 44 adiciones y 19 borrados
  1. 24 9
      devstone/pythonpdevs/devstone.py
  2. 8 3
      devstone/pythonpdevs/main.py
  3. 12 7
      devstone/testPyPDEVS.py

+ 24 - 9
devstone/pythonpdevs/devstone.py

@@ -190,7 +190,7 @@ class DEVStoneWrapper(CoupledDEVS, ABC):
             result += f"\t{model.name}[shape=ellipse, label=\"{'A_' + '_'.join(model.name.split('_')[1:3])}\"];\n"
 
         for connections in self.i_in.outline:
-            result += f"\tCoupled_{self.depth}:i_in -> {str(connections).split('.')[2]}:{connections.name};\n"
+            result += f"\tCoupled_{self.depth}:i_in -> {str(connections).split('.')[-2]}:{connections.name};\n"
 
         for model in self.models:
             if not hasattr(model, "o_out"):
@@ -434,23 +434,28 @@ class dLI(DEVStoneWrapper):
     """
     A LI model which grows in width
     """
-    def __init__(self, name: str, depth: int, width: int, int_delay: float, ext_delay: float, prep_time=0, stats=False):
+    def __init__(self, name: str, depth: int, width: int, int_delay: float, ext_delay: float, generator_mode: str = "uniform", root=True, prep_time=0, stats=False):
         super().__init__(name, depth, width, int_delay, ext_delay, add_atomic_out_ports=False, prep_time=prep_time,
                          stats=stats, mode="LI-Dynamic", dynamic=True)
 
+        self.root = root
         for idx in range(1, len(self.component_set)):
             assert isinstance(self.component_set[idx], AtomicDEVS)
             self.connectPorts(self.i_in, self.component_set[idx].i_in)
 
         self.current_width = 1
         self.max_gen = width - 1 # dynamically generate atomic components until width is reached excludes the coupled model
-        self.generator = self.addSubModel(DynamicGenerator(self.name + "_gen", repeat=self.max_gen))
+        if self.depth == 1:
+            self.generator = self.addSubModel(DynamicGenerator(self.name + "_gen", repeat=self.max_gen))
 
     def gen_coupled(self):
         return dLI("Coupled_%d" % (self.depth - 1), self.depth - 1, self.width, self.int_delay, self.ext_delay,
-                   prep_time=self.prep_time, stats=self.stats)
+                   prep_time=self.prep_time, stats=self.stats, root=False)
 
     def modelTransition(self, state):
+        if state.get("generate", True) and self.depth == 1:
+            return True
+
         if state.get("generate", True) and self.depth > 1:
             name = "Atomic_%d_%d" % (self.depth - 1, self.current_width) if self.depth > 1 else "Atomic_0_%d" % self.current_width
             if self.stats:
@@ -464,7 +469,10 @@ class dLI(DEVStoneWrapper):
             self.connectPorts(self.i_in, new_atom.i_in)
 
             self.current_width += 1
-            # print(f"{self.name}: added {new_atom.name} (width is now {self.width})")
+            # if self.current_width == self.width:
+            #     self.dot(f"dLI_{self.depth}")
+            if not self.root:
+                return True
             return False
         return False
 
@@ -473,10 +481,11 @@ class dHI(DEVStoneWrapper):
     """
     A HI model which grows in width
     """
-    def __init__(self, name: str, depth: int, width: int, int_delay: float, ext_delay: float, prep_time=0, stats=False):
+    def __init__(self, name: str, depth: int, width: int, int_delay: float, ext_delay: float, generator_mode: str = "uniform", root=True, prep_time=0, stats=False):
         super().__init__(name, depth, width, int_delay, ext_delay, add_atomic_out_ports=True, prep_time=prep_time,
                          stats=stats, mode="HI-Dynamic", dynamic=True)
 
+        self.root = root
         if len(self.component_set) > 1:
             assert isinstance(self.component_set[-1], AtomicDEVS)
             self.connectPorts(self.i_in, self.component_set[-1].i_in)
@@ -488,13 +497,17 @@ class dHI(DEVStoneWrapper):
 
         self.current_width = 1
         self.max_gen = width - 1 # dynamically generate atomic components until width is reached excludes the coupled model
-        self.generator = self.addSubModel(DynamicGenerator(self.name + "_gen", repeat=self.max_gen))
+        if self.depth == 1:
+            self.generator = self.addSubModel(DynamicGenerator(self.name + "_gen", repeat=self.max_gen))
 
     def gen_coupled(self):
         return dHI("Coupled_%d" % (self.depth - 1), self.depth - 1, self.width, self.int_delay, self.ext_delay,
-                   prep_time=self.prep_time, stats=self.stats)
+                   prep_time=self.prep_time, stats=self.stats, root=False)
 
     def modelTransition(self, state):
+        if state.get("generate", True) and self.depth == 1:
+            return True
+
         if state.get("generate", True) and self.depth > 1:
             name = "Atomic_%d_%d" % (self.depth - 1, self.current_width) if self.depth > 1 else "Atomic_0_%d" % self.current_width
             if self.stats:
@@ -508,11 +521,13 @@ class dHI(DEVStoneWrapper):
             self.connectPorts(self.i_in, new_atom.i_in)
             if len(self.models) > 1:
                 prev = self.models[-2]
-                print("last: ", prev.name)
+                # print("last: ", prev.name)
                 if isinstance(prev, AtomicDEVS) and hasattr(prev, "o_out"):
                     self.connectPorts(prev.o_out, new_atom.i_in)
 
             self.current_width += 1
+            if not self.root:
+                return True
             return False
         return False
 

+ 8 - 3
devstone/pythonpdevs/main.py

@@ -25,6 +25,7 @@ class DEVStoneEnvironment(CoupledDEVS):
 
 
 MODEL_TYPES = ("LI", "HI", "HO", "HOmod", "LI2HI", "HI2LI", "dLI", "dHI")
+GEN_METHODS = ("start", "uniform", "end")
 
 
 def parse_args():
@@ -40,6 +41,7 @@ def parse_args():
 
     parser.add_argument('-C', '--classic', action="store_true", default=False, help='Use classic DEVS simulator')
     parser.add_argument('-D', '--dynamic', action="store_true", default=False, help='Enables Dynamic Structure DEVS')
+    parser.add_argument("-g", "--gen-mode", choices=GEN_METHODS, help="Determines the spread of model creation.")
     args = parser.parse_args()
 
     if args.model_type not in MODEL_TYPES:
@@ -68,13 +70,15 @@ if __name__ == '__main__':
     elif args.model_type == "HI2LI":
         devstone_model = HI2LI("HI2LI_root", args.depth, args.width, args.int_cycles, args.ext_cycles, prep_time=1)
     elif args.model_type == "dLI":
-        devstone_model = dLI("dLI_root", args.depth, args.width, args.int_cycles, args.ext_cycles, prep_time=1)
+        devstone_model = dLI("dLI_root", args.depth, args.width, args.int_cycles, args.ext_cycles, args.gen_mode, prep_time=1)
     elif args.model_type == "dHI":
-        devstone_model = dHI("dHI_root", args.depth, args.width, args.int_cycles, args.ext_cycles, prep_time=1)
+        devstone_model = dHI("dHI_root", args.depth, args.width, args.int_cycles, args.ext_cycles, args.gen_mode, prep_time=1)
 
     env = DEVStoneEnvironment("DEVStoneEnvironment", devstone_model)
     model_created_time = time.time()
+
     # print(devstone_model)
+    # devstone_model.dot(f"{args.model_type}-before")
 
     sim = Simulator(env)
     if args.classic:
@@ -87,8 +91,9 @@ if __name__ == '__main__':
     engine_setup_time = time.time()
     sim.simulate()
     sim_time = time.time()
+
     # print(devstone_model)
-    # devstone_model.dot()
+    # devstone_model.dot(f"{args.model_type}-after")
 
     print("Model creation time: {}".format(model_created_time - start_time))
     print("Engine setup time: {}".format(engine_setup_time - model_created_time))

+ 12 - 7
devstone/testPyPDEVS.py

@@ -6,8 +6,10 @@ from argparse import ArgumentParser, Action
 from itertools import product
 from datetime import datetime
 
-MODEL_TYPES = ["LI", "HI", "HO", "HOmod"]
-DS_MODEL_TYPES = ["LI2HI", "HI2LI", "LI-HI", "dLI", "dHI"]
+MODEL_TYPES = ("LI", "HI", "HO", "HOmod")
+DS_MODEL_TYPES = ("LI2HI", "HI2LI", "LI-HI", "dLI", "dHI")
+GEN_METHODS = ("start", "uniform", "end")
+
 INT_CYCLES = 0
 EXT_CYCLES = 0
 
@@ -22,7 +24,7 @@ TIME_PATTERN = re.compile(
     re.S
 )
 
-def run_devstone(model_type, depth, width, minimal=False, classic=False, dynamic=False):
+def run_devstone(model_type, depth, width, minimal=False, classic=False, dynamic=False, gen_mode="uniform"):
     """Runs the devstone_driver.py script and returns timing results as floats."""
     SCRIPT_PATH = PyPDEVS
     if minimal:
@@ -38,11 +40,12 @@ def run_devstone(model_type, depth, width, minimal=False, classic=False, dynamic
     ]
     if dynamic and not minimal:
         cmd.extend(["-D"])
+        cmd.extend(["-g", gen_mode])
     if classic and not minimal:
         cmd.extend(["-C"])
     result = subprocess.run(cmd, capture_output=True, text=True)
     output = result.stdout.strip()
-    # print(output)
+    print(output)
     errors = result.stderr.strip()
     match = TIME_PATTERN.search(output)
 
@@ -69,6 +72,7 @@ def parse_args():
     parser.add_argument("-M", "--minimal", action="store_true", default=False, help="Uses the minimal DEVS kernel. (Less features => less overhead)")
     parser.add_argument("-C", "--classic", action="store_true", default=False, help="Selects the Classic DEVS Simulator")
     parser.add_argument("-D", "--dynamic", action="store_true", default=False, help="Enables Dynamic Structure DEVS")
+    parser.add_argument("-g", "--gen-mode", choices=GEN_METHODS, default="uniform", help="Determines the spread of model creation.")
 
     parser.add_argument("-ms", "--model-structure", nargs="+", default=MODEL_TYPES+DS_MODEL_TYPES, choices=MODEL_TYPES+DS_MODEL_TYPES, help="Select one or more model structures")
 
@@ -95,7 +99,7 @@ if __name__ == "__main__":
         raise RuntimeError("Invalid width stepsize.")
 
     fieldnames = ["model_type", "depth", "width", "run",
-                  "creation_time", "setup_time", "simulation_time"]
+                  "creation_time", "setup_time", "simulation_time", "generator_mode"]
 
     for model_type in args.model_structure:
         model_filename = f"{args.path}{model_type}"
@@ -112,7 +116,7 @@ if __name__ == "__main__":
                     for run in range(args.repetitions):
                         creation, setup, sim, output = run_devstone(
                             model_type, depth, width,
-                            args.minimal, args.classic, args.dynamic
+                            args.minimal, args.classic, args.dynamic, args.gen_mode
                         )
                         if creation is not None:
                             writer.writerow({
@@ -122,7 +126,8 @@ if __name__ == "__main__":
                                 "run": run,
                                 "creation_time": creation,
                                 "setup_time": setup,
-                                "simulation_time": sim
+                                "simulation_time": sim,
+                                "generator_mode": args.gen_mode
                             })
                             csvfile.flush()
         print(f"✅ Saved {model_type} results to {model_filename}")