def __init__(self, world = None, logenabled = True, logOutput = True, logMemory = True, metaEnabled = False, phaseManager = None, verbose = 2): self.world = world self.mem = Memory() self.phases = [] self.metaPhases = [] self.modules = {} self.metaModules = {} self.verbose = verbose self.initialized = False self.phaseNum = 1 self.metaPhaseNum = 1 self.logger = logging.Logger() self.metaEnabled = metaEnabled if metaEnabled: if not phaseManager: raise Exception("MetaEnabled but phaseManager pointer not given") self.mem.enableMeta(trace.CogTrace(), phaseManager) # self is pointer to midca itself if not logenabled: self.logger.working = False else: self.logger.start() if self.logger.working: if logOutput: self.logger.logOutput() self.mem.enableLogging(self.logger) self.mem.logEachAccess = logMemory
def copy(self): ''' This method does not make a true copy - it will not copy the original object's loggers and is not intended to be run, only checked to see what MIDCA's state was at an earlier time. ''' newCopy = MIDCA(self.world, False, self.verbose) newCopy.mem = Memory() newCopy.mem.knowledge = self.mem.knowledge.copy() newCopy.mem.locks = {name: threading.Lock() for name in self.mem.locks} newCopy.phases = list(self.phases) newCopy.modules = self.modules.copy() newCopy.initialized = self.initialized newCopy.phaseNum = self.phaseNum return newCopy
class MIDCA: def __init__(self, world=None, logenabled=True, logOutput=True, logMemory=True, metaEnabled=False, phaseManager=None, verbose=2): self.world = world self.mem = Memory() self.phases = [] self.metaPhases = [] self.modules = {} self.metaModules = {} self.verbose = verbose self.initialized = False self.phaseNum = 1 self.metaPhaseNum = 1 self.logger = logging.Logger(verbose=verbose) self.metaEnabled = metaEnabled if metaEnabled: self.mem.enableTrace() if not phaseManager: raise Exception( "MetaEnabled but phaseManager pointer not given") self.mem.enableMeta(phaseManager) if not logenabled: self.logger.working = False else: self.logger.start() if self.logger.working: if logOutput: self.logger.logOutput() self.mem.enableLogging(self.logger) self.mem.logEachAccess = logMemory def phase_by_name(self, name, meta=False): phases = self.phases if meta: phases = self.metaPhases for phase in phases: if phase.name == name: return phase return None def insert_phase(self, phase, phaseOrIndex, meta=False): phases = self.phases modules = self.modules if meta: # switch if inserting a meta phase phases = self.metaPhases modules = self.metaModules if isinstance(phase, str): phase = Phase(phase) if not isinstance(phase, Phase): raise KeyError(str(phase) + " is not a valid phase or phase name.") if isinstance(phaseOrIndex, str): phaseOrIndex = self.phase_by_name(phaseOrIndex, meta) elif isinstance(phaseOrIndex, int): phases.insert(phaseOrIndex, phase) modules[phase] = [] return if not isinstance(phaseOrIndex, Phase): raise KeyError(str(phase) + " is not a valid phase or index.") if phaseOrIndex not in self.phases: raise KeyError("phase " + str(phaseOrIndex) + " not in phase list.") phases.insert(self.phases.index(phaseOrIndex), phase) modules[phase] = [] def append_phase(self, phase, meta=False): if meta: self.insert_phase(phase, len(self.metaPhases) + 1, meta) else: self.insert_phase(phase, len(self.phases) + 1, meta) def remove_phase(self, phaseOrName): if isinstance(phaseOrName, str): phase = self.phase_by_name(phaseOrName) else: phase = phaseOrName try: self.phases.remove(phase) del self.modules[phase] except ValueError: raise ValueError("Phase " + str(phaseOrName) + " is not a phase.") #if there is a KeyError, something has gone very wrong. def append_module(self, phase, module, meta=False): self.insert_module(phase, module, MAX_MODULES_PER_PHASE, meta) def runtime_append_module(self, phase, module): self.runtime_insert_module(phase, module, MAX_MODULES_PER_PHASE) #note: error handling should be cleaned up - if a phase cannot be found by name, the error will report the phase name as "None" instead of whatever was given. True for removeModule as well. def insert_module(self, phase, module, i, meta=False): phases = self.phases modules = self.modules if meta: phases = self.metaPhases modules = self.metaModules if isinstance(phase, str): phase = self.phase_by_name(phase, meta) if phase not in phases: raise KeyError( "phase " + str(phase) + " not in phase list. Call insert_phase() or append_phase() to add it." ) if not hasattr(module, "run"): raise AttributeError("All modules must a 'run' function") if len(modules[phase]) == MAX_MODULES_PER_PHASE: raise Exception("max module per phase [" + str(MAX_MODULES_PER_PHASE) + "] exceeded for phase" + str(phase) + ". Cannot add another.") modules[phase].insert(i, module) # just like insert_module but also calls module.init() def runtime_insert_module(self, phase, module, i): if isinstance(phase, str): phase = self.phase_by_name(phase) if phase not in self.phases: raise KeyError( "phase " + str(phase) + " not in phase list. Call insert_phase() or append_phase() to add it." ) if not hasattr(module, "run"): raise AttributeError("All modules must a 'run' function") if len(self.modules[phase]) == MAX_MODULES_PER_PHASE: raise Exception("max module per phase [" + str(MAX_MODULES_PER_PHASE) + "] exceeded for phase" + str(phase) + ". Cannot add another.") self.modules[phase].insert(i, module) try: # TODO: hacky fix for having modules with two kinds of init functions (one with verbose and one without) # some modules use verbose to get the new verbose value # and others don't module.init(mem=self.mem, world=self.world, verbose=self.verbose) except: module.init(mem=self.mem, world=self.world) def removeModule(self, phase, i): if isinstance(phase, str): phase = self.phase_by_name(phase) if phase not in self.modules: raise KeyError( "phase " + str(phase) + " not in phase list. Call insert_phase() or append_phase() to add it." ) modules = self.modules[phase] if i < 0 or i >= len(modules): raise IndexError( "index " + str(i) + " is outside the range of the module list for phase " + str(phase)) else: return modules.pop(i) def clearPhase(self, phaseOrName): if isinstance(phaseOrName, str): phase = self.phase_by_name(phaseOrName) else: phase = phaseOrName try: self.modules[phase] = [] except ValueError: raise ValueError("Phase " + str(phaseOrName) + " is not a phase.") def get_modules(self, phase): if isinstance(phase, str): phase = self.phase_by_name(phase) if phase in self.modules: return self.modules[phase] else: raise ValueError("No such phase as " + str(phase)) def init(self): self.init_cognitive_layer(verbose=self.verbose) if self.metaEnabled: self.init_metacognitive_layer(verbose=self.verbose) def init_cognitive_layer(self, verbose=2): for phase in self.phases: modules = self.modules[phase] i = 0 for module in modules: i += 1 try: if verbose >= 2: print("[cognitive] Initializing " + phase.name + " module " + str(i) + " " + str(module.__class__.__name__) + "...", end="") module.init(world=self.world, mem=self.mem) if verbose >= 2: print("done.") except Exception as e: print(e) if verbose >= 2: print( "\n[cognitive] Phase " + phase.name + " module " + str(i) + " " + str(module.__class__.__name__) + " has no init function or had an error. Skipping init." ) self.initGoalGraph(overwrite=False) self.initialized = True def init_metacognitive_layer(self, verbose=2): for phase in self.metaPhases: modules = self.metaModules[phase] i = 0 for module in modules: i += 1 try: if verbose >= 2: print("[metacognitive] Initializing " + phase.name + " module " + str(i) + " " + str(module.__class__.__name__) + "...", end="") module.init(world=self.world, mem=self.mem) if verbose >= 2: print("done.") except Exception as e: print(e) if verbose >= 2: print( "\n[metacognitive] Phase " + phase.name + " module " + str(i) + " " + str(module.__class__.__name__) + "has no init function or had an error. Skipping init." ) self.initGoalGraph(overwrite=False) self.initialized = True def initGoalGraph(self, cmpFunc=None, overwrite=True): if overwrite or not self.mem.get(self.mem.GOAL_GRAPH): self.mem.set(self.mem.GOAL_GRAPH, goals.GoalGraph(cmpFunc)) if self.verbose > 0: print("Goal Graph initialized.", ) if cmpFunc: if self.verbose > 0: print() else: if self.verbose > 0: print( "To use goal ordering, call initGoalGraph manually with a custom goal comparator" ) def next_phase(self, verbose=2, meta=False): phaseNum = self.phaseNum phases = self.phases modules = self.modules if meta: # switch if meta phaseNum = self.metaPhaseNum phases = self.metaPhases modules = self.metaModules retVal = "" self.phasei = (phaseNum - 1) % len(phases) if self.phasei == 0: if self.logger.working: self.logger.logEvent( logging.CycleStartEvent((phaseNum - 1) / len(phases))) if verbose >= 2: if meta: print(" ***[meta] Starting ", phases[self.phasei].name, "Phase ***\n", file=sys.stderr) else: print("****** Starting", phases[self.phasei].name, "Phase ******\n", file=sys.stderr) if self.logger.working: self.logger.logEvent( logging.PhaseStartEvent(phases[self.phasei].name)) i = 0 while i < len(modules[phases[self.phasei]]): module = modules[phases[self.phasei]][i] if self.logger.working: self.logger.logEvent(logging.ModuleStartEvent(module)) try: retVal = module.run((phaseNum - 1) / len(phases), verbose) i += 1 except NotImplementedError: if verbose >= 1: print("module", module, "does not", "implement the run() method and", "is therefore invalid. It will be", "removed from MIDCA.") self.removeModule(phases[self.phasei], i) if self.logger.working: self.logger.logEvent(logging.ModuleEndEvent(module)) if self.logger.working: self.logger.logEvent( logging.PhaseEndEvent(phases[self.phasei].name)) if not meta: self.phaseNum += 1 else: self.metaPhaseNum += 1 if (phaseNum - 1) % len(phases) == 0: if self.logger.working: self.logger.logEvent( logging.CycleEndEvent((phaseNum - 1) / len(phases))) # record phase and run metareasoner #self.mem.set("phase", self.phases[self.phasei].name) #metareasoner.MetaReasoner(self.trace, self.mem).run() return retVal def copy(self): ''' This method does not make a true copy - it will not copy the original object's loggers and is not intended to be run, only checked to see what MIDCA's state was at an earlier time. ''' newCopy = MIDCA(self.world, False, self.verbose) newCopy.mem = Memory() newCopy.mem.knowledge = self.mem.knowledge.copy() newCopy.mem.locks = {name: threading.Lock() for name in self.mem.locks} newCopy.phases = list(self.phases) newCopy.modules = self.modules.copy() newCopy.initialized = self.initialized newCopy.phaseNum = self.phaseNum return newCopy
class MIDCA: def __init__(self, world = None, logenabled = True, logOutput = True, logMemory = True, metaEnabled = False, phaseManager = None, verbose = 2): self.world = world self.mem = Memory() self.phases = [] self.metaPhases = [] self.modules = {} self.metaModules = {} self.verbose = verbose self.initialized = False self.phaseNum = 1 self.metaPhaseNum = 1 self.logger = logging.Logger() self.metaEnabled = metaEnabled if metaEnabled: if not phaseManager: raise Exception("MetaEnabled but phaseManager pointer not given") self.mem.enableMeta(trace.CogTrace(), phaseManager) # self is pointer to midca itself if not logenabled: self.logger.working = False else: self.logger.start() if self.logger.working: if logOutput: self.logger.logOutput() self.mem.enableLogging(self.logger) self.mem.logEachAccess = logMemory def phase_by_name(self, name, meta = False): phases = self.phases if meta: phases = self.metaPhases for phase in phases: if phase.name == name: return phase return None def insert_phase(self, phase, phaseOrIndex, meta = False): phases = self.phases modules = self.modules if meta: # switch if inserting a meta phase phases = self.metaPhases modules = self.metaModules if isinstance(phase, str): phase = Phase(phase) if not isinstance(phase, Phase): raise KeyError(str(phase) + " is not a valid phase or phase name.") if isinstance(phaseOrIndex, str): phaseOrIndex = self.phase_by_name(phaseOrIndex, meta) elif isinstance(phaseOrIndex, int): phases.insert(phaseOrIndex, phase) modules[phase] = [] return if not isinstance(phaseOrIndex, Phase): raise KeyError(str(phase) + " is not a valid phase or index.") if phaseOrIndex not in self.phases: raise KeyError("phase " + str(phaseOrIndex) + " not in phase list.") phases.insert(self.phases.index(phaseOrIndex), phase) modules[phase] = [] def append_phase(self, phase, meta=False): if meta: self.insert_phase(phase, len(self.metaPhases) + 1, meta) else: self.insert_phase(phase, len(self.phases) + 1, meta) def remove_phase(self, phaseOrName): if isinstance(phaseOrName, str): phase = self.phase_by_name(phaseOrName) else: phase = phaseOrName try: self.phases.remove(phase) del self.modules[phase] except ValueError: raise ValueError("Phase " + str(phaseOrName) + " is not a phase.") #if there is a KeyError, something has gone very wrong. def append_module(self, phase, module, meta=False): self.insert_module(phase, module, MAX_MODULES_PER_PHASE, meta) def runtime_append_module(self, phase, module): self.runtime_insert_module(phase, module, MAX_MODULES_PER_PHASE) #note: error handling should be cleaned up - if a phase cannot be found by name, the error will report the phase name as "None" instead of whatever was given. True for removeModule as well. def insert_module(self, phase, module, i, meta=False): phases = self.phases modules = self.modules if meta: phases = self.metaPhases modules = self.metaModules if isinstance(phase, str): phase = self.phase_by_name(phase, meta) if phase not in phases: raise KeyError("phase " + str(phase) + " not in phase list. Call insert_phase() or append_phase() to add it.") if not hasattr(module, "run"): raise AttributeError("All modules must a 'run' function") if len(modules[phase]) == MAX_MODULES_PER_PHASE: raise Exception("max module per phase [" + str(MAX_MODULES_PER_PHASE) + "] exceeded for phase" + str(phase) + ". Cannot add another.") modules[phase].insert(i, module) # just like insert_module but also calls module.init() def runtime_insert_module(self, phase, module, i): if isinstance(phase, str): phase = self.phase_by_name(phase) if phase not in self.phases: raise KeyError("phase " + str(phase) + " not in phase list. Call insert_phase() or append_phase() to add it.") if not hasattr(module, "run"): raise AttributeError("All modules must a 'run' function") if len(self.modules[phase]) == MAX_MODULES_PER_PHASE: raise Exception("max module per phase [" + str(MAX_MODULES_PER_PHASE) + "] exceeded for phase" + str(phase) + ". Cannot add another.") self.modules[phase].insert(i, module) module.init(mem=self.mem, world=self.world) def removeModule(self, phase, i): if isinstance(phase, str): phase = self.phase_by_name(phase) if phase not in self.modules: raise KeyError("phase " + str(phase) + " not in phase list. Call insert_phase() or append_phase() to add it.") modules = self.modules[phase] if i < 0 or i >= len(modules): raise IndexError("index " + str(i) + " is outside the range of the module list for phase " + str(phase)) else: modules.pop(i) def clearPhase(self, phaseOrName): if isinstance(phaseOrName, str): phase = self.phase_by_name(phaseOrName) else: phase = phaseOrName try: self.modules[phase] = [] except ValueError: raise ValueError("Phase " + str(phaseOrName) + " is not a phase.") def get_modules(self, phase): if isinstance(phase, str): phase = self.phase_by_name(phase) if phase in self.modules: return self.modules[phase] else: raise ValueError("No such phase as " + str(phase)) def init(self, verbose = 2): self.init_cognitive_layer(verbose) if self.metaEnabled: self.init_metacognitive_layer(verbose) def init_cognitive_layer(self, verbose = 2): for phase in self.phases: modules = self.modules[phase] i = 0 for module in modules: i += 1 try: if verbose >= 2: print("[cognitive] Initializing " + phase.name + " module " + str(i) + "...",end="") module.init(world = self.world, mem = self.mem) print("done.") except Exception as e: print(e) if verbose >= 2: print("\n[cognitive] Phase " + phase.name + " module " + str(i) + " has no init function or had an error. Skipping init.") self.initGoalGraph(overwrite = False) self.initialized = True def init_metacognitive_layer(self, verbose = 2): for phase in self.metaPhases: modules = self.metaModules[phase] i = 0 for module in modules: i += 1 try: if verbose >= 2: print("[metacognitive] Initializing " + phase.name + " module " + str(i) + "...",end="") module.init(world = self.world, mem = self.mem) print("done.") except Exception as e: print(e) if verbose >= 2: print("\n[metacognitive] Phase " + phase.name + " module " + str(i) + "has no init function or had an error. Skipping init.") self.initGoalGraph(overwrite = False) self.initialized = True def initGoalGraph(self, cmpFunc = None, overwrite = True): if overwrite or not self.mem.get(self.mem.GOAL_GRAPH): self.mem.set(self.mem.GOAL_GRAPH, goals.GoalGraph(cmpFunc)) print("Goal Graph initialized.",) if cmpFunc: print() else: print("To use goal ordering, call initGoalGraph manually with a custom goal comparator") def next_phase(self, verbose = 2, meta = False): phaseNum = self.phaseNum phases = self.phases modules = self.modules if meta: # switch if meta phaseNum = self.metaPhaseNum phases = self.metaPhases modules = self.metaModules retVal = "" self.phasei = (phaseNum - 1) % len(phases) if self.phasei == 0: self.logger.logEvent(logging.CycleStartEvent((phaseNum - 1) / len(phases))) if verbose >= 2: if meta: print(" ***[meta] Starting ", phases[self.phasei].name, "Phase ***\n", file = sys.stderr) else: print("****** Starting", phases[self.phasei].name, "Phase ******\n", file = sys.stderr) self.logger.logEvent(logging.PhaseStartEvent(phases[self.phasei].name)) i = 0 while i < len(modules[phases[self.phasei]]): module = modules[phases[self.phasei]][i] self.logger.logEvent(logging.ModuleStartEvent(module)) try: retVal = module.run((phaseNum - 1) / len(phases), verbose) i += 1 except NotImplementedError: if verbose >= 1: print("module", module, "does not", "implement the run() method and", "is therefore invalid. It will be", "removed from MIDCA.") self.removeModule(phases[self.phasei], i) self.logger.logEvent(logging.ModuleEndEvent(module)) self.logger.logEvent(logging.PhaseEndEvent(phases[self.phasei].name)) if not meta: self.phaseNum += 1 else: self.metaPhaseNum += 1 if (phaseNum - 1) % len(phases) == 0: self.logger.logEvent(logging.CycleEndEvent((phaseNum - 1) / len(phases))) # record phase and run metareasoner #self.mem.set("phase", self.phases[self.phasei].name) #metareasoner.MetaReasoner(self.trace, self.mem).run() return retVal def copy(self): ''' This method does not make a true copy - it will not copy the original object's loggers and is not intended to be run, only checked to see what MIDCA's state was at an earlier time. ''' newCopy = MIDCA(self.world, False, self.verbose) newCopy.mem = Memory() newCopy.mem.knowledge = self.mem.knowledge.copy() newCopy.mem.locks = {name: threading.Lock() for name in self.mem.locks} newCopy.phases = list(self.phases) newCopy.modules = self.modules.copy() newCopy.initialized = self.initialized newCopy.phaseNum = self.phaseNum return newCopy