Преглед изворни кода

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 пре 2 месеци
родитељ
комит
1cbe3563ee
3 измењених фајлова са 44 додато и 19 уклоњено
  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}")