From a3b122b75c60e009f20efa0ccad5aec21a45a7c1 Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Sun, 16 Apr 2017 21:12:39 -0700 Subject: [PATCH] Massive overhaul of "codelet methods" and the coderack. Should be no functional change, but this gets rid of one circular import (some codelet methods need a pointer to the coderack, but they should be getting that pointer from their caller, not from the global scope) and a lot of reflection-magic. --- copycat/codeletMethods.py | 88 ++++++++++++++++++++++------------ copycat/coderack.py | 99 +++++++++------------------------------ 2 files changed, 80 insertions(+), 107 deletions(-) diff --git a/copycat/codeletMethods.py b/copycat/codeletMethods.py index ba78098..76996de 100644 --- a/copycat/codeletMethods.py +++ b/copycat/codeletMethods.py @@ -1,15 +1,12 @@ - - -import random +import inspect import logging - +import random from slipnet import slipnet import temperature import formulas from workspaceFormulas import chooseDirectedNeighbor from workspaceFormulas import chooseNeighbor -from coderack import coderack from workspaceObject import WorkspaceObject from letter import Letter from replacement import Replacement @@ -21,6 +18,14 @@ from correspondence import Correspondence from workspaceFormulas import chooseUnmodifiedObject from workspaceFormulas import chooseBondFacet +def codelet(name): + """Decorator for otherwise-unused functions that are in fact used as codelet behaviors""" + def wrap(f): + assert tuple(inspect.getargspec(f)) == (['coderack', 'codelet'], None, None, None) + f.is_codelet_method = True + f.codelet_name = name + return f + return wrap # some methods common to the codelets def __showWhichStringObjectIsFrom(structure): @@ -123,8 +128,8 @@ def __slippability(conceptMappings): return False -# start the actual codelets -def breaker(): +@codelet('breaker') +def breaker(coderack, codelet): probabilityOfFizzle = (100.0 - formulas.Temperature) / 100.0 assert not formulas.coinFlip(probabilityOfFizzle) # choose a structure at random @@ -148,7 +153,8 @@ def breaker(): structure.break_the_structure() -def bottom_up_description_scout(codelet): +@codelet('bottom-up-description-scout') +def bottom_up_description_scout(coderack, codelet): chosenObject = chooseUnmodifiedObject('totalSalience', workspace.objects) assert chosenObject __showWhichStringObjectIsFrom(chosenObject) @@ -165,7 +171,8 @@ def bottom_up_description_scout(codelet): chosenProperty, codelet) -def top_down_description_scout(codelet): +@codelet('top-down-description-scout') +def top_down_description_scout(coderack, codelet): descriptionType = codelet.arguments[0] chosenObject = chooseUnmodifiedObject('totalSalience', workspace.objects) assert chosenObject @@ -179,7 +186,8 @@ def top_down_description_scout(codelet): chosenProperty, codelet) -def description_strength_tester(codelet): +@codelet('description-strength-tester') +def description_strength_tester(coderack, codelet): description = codelet.arguments[0] description.descriptor.buffer = 100.0 description.updateStrength() @@ -189,7 +197,8 @@ def description_strength_tester(codelet): coderack.newCodelet('description-builder', codelet, strength) -def description_builder(codelet): +@codelet('description-builder') +def description_builder(coderack, codelet): description = codelet.arguments[0] assert description.object in workspace.objects if description.object.described(description.descriptor): @@ -199,7 +208,8 @@ def description_builder(codelet): description.build() -def bottom_up_bond_scout(codelet): +@codelet('bottom-up-bond-scout') +def bottom_up_bond_scout(coderack, codelet): source = chooseUnmodifiedObject('intraStringSalience', workspace.objects) __showWhichStringObjectIsFrom(source) destination = chooseNeighbor(source) @@ -222,7 +232,8 @@ def bottom_up_bond_scout(codelet): sourceDescriptor, destinationDescriptor, codelet) -def rule_scout(codelet): +@codelet('rule-scout') +def rule_scout(coderack, codelet): assert workspace.numberOfUnreplacedObjects() == 0 changedObjects = [o for o in workspace.initial.objects if o.changed] #assert len(changedObjects) < 2 @@ -284,7 +295,8 @@ def rule_scout(codelet): slipnet.letter, relation, codelet) -def rule_strength_tester(codelet): +@codelet('rule-strength-tester') +def rule_strength_tester(coderack, codelet): rule = codelet.arguments[0] rule.updateStrength() probability = formulas.temperatureAdjustedProbability( @@ -293,7 +305,8 @@ def rule_strength_tester(codelet): coderack.newCodelet('rule-builder', codelet, rule.totalStrength, rule) -def replacement_finder(): +@codelet('replacement-finder') +def replacement_finder(coderack, codelet): # choose random letter in initial string letters = [o for o in workspace.initial.objects if isinstance(o, Letter)] letterOfInitialString = random.choice(letters) @@ -330,7 +343,8 @@ def replacement_finder(): logging.info('building replacement') -def top_down_bond_scout__category(codelet): +@codelet('top-down-bond-scout--category') +def top_down_bond_scout__category(coderack, codelet): logging.info('top_down_bond_scout__category') category = codelet.arguments[0] source = __getScoutSource(category, formulas.localBondCategoryRelevance, @@ -358,7 +372,8 @@ def top_down_bond_scout__category(codelet): sourceDescriptor, codelet) -def top_down_bond_scout__direction(codelet): +@codelet('top-down-bond-scout--direction') +def top_down_bond_scout__direction(coderack, codelet): direction = codelet.arguments[0] source = __getScoutSource( direction, formulas.localDirectionCategoryRelevance, 'bond') @@ -376,7 +391,8 @@ def top_down_bond_scout__direction(codelet): sourceDescriptor, destinationDescriptor, codelet) -def bond_strength_tester(codelet): +@codelet('bond-strength-tester') +def bond_strength_tester(coderack, codelet): bond = codelet.arguments[0] __showWhichStringObjectIsFrom(bond) bond.updateStrength() @@ -391,7 +407,8 @@ def bond_strength_tester(codelet): coderack.newCodelet('bond-builder', codelet, strength) -def bond_builder(codelet): +@codelet('bond-builder') +def bond_builder(coderack, codelet): bond = codelet.arguments[0] __showWhichStringObjectIsFrom(bond) bond.updateStrength() @@ -433,7 +450,8 @@ def bond_builder(codelet): # pylint: disable=too-many-branches # pylint: disable=too-many-statements -def top_down_group_scout__category(codelet): +@codelet('top-down-group-scout--category') +def top_down_group_scout__category(coderack, codelet): groupCategory = codelet.arguments[0] category = groupCategory.getRelatedNode(slipnet.bondCategory) assert category @@ -515,7 +533,8 @@ def top_down_group_scout__category(codelet): direction, bondFacet, codelet) -def top_down_group_scout__direction(codelet): +@codelet('top-down-group-scout--direction') +def top_down_group_scout__direction(coderack, codelet): direction = codelet.arguments[0] source = __getScoutSource(direction, formulas.localDirectionCategoryRelevance, @@ -606,7 +625,8 @@ def top_down_group_scout__direction(codelet): #noinspection PyStringFormat -def group_scout__whole_string(codelet): +@codelet('group-scout--whole-string') +def group_scout__whole_string(coderack, codelet): string = workspace.initial if random.random() > 0.5: string = workspace.target @@ -646,7 +666,8 @@ def group_scout__whole_string(codelet): bondFacet, codelet) -def group_strength_tester(codelet): +@codelet('group-strength-tester') +def group_strength_tester(coderack, codelet): # update strength value of the group group = codelet.arguments[0] __showWhichStringObjectIsFrom(group) @@ -661,7 +682,8 @@ def group_strength_tester(codelet): coderack.newCodelet('group-builder', codelet, strength) -def group_builder(codelet): +@codelet('group-builder') +def group_builder(coderack, codelet): # update strength value of the group group = codelet.arguments[0] #print '%s' % group @@ -735,7 +757,8 @@ def group_builder(codelet): logging.info('building group') -def rule_builder(codelet): +@codelet('rule-builder') +def rule_builder(coderack, codelet): rule = codelet.arguments[0] if rule.ruleEqual(workspace.rule): rule.activateRuleDescriptions() @@ -768,7 +791,8 @@ def __getCutOff(density): return len(distribution) -def rule_translator(): +@codelet('rule-translator') +def rule_translator(coderack, codelet): assert workspace.rule if len(workspace.initial) == 1 and len(workspace.target) == 1: bondDensity = 1.0 @@ -789,7 +813,8 @@ def rule_translator(): formulas.Temperature = 100.0 -def bottom_up_correspondence_scout(codelet): +@codelet('bottom-up-correspondence-scout') +def bottom_up_correspondence_scout(coderack, codelet): objectFromInitial = chooseUnmodifiedObject('interStringSalience', workspace.initial.objects) objectFromTarget = chooseUnmodifiedObject('interStringSalience', @@ -826,7 +851,8 @@ def bottom_up_correspondence_scout(codelet): conceptMappings, flipTargetObject, codelet) -def important_object_correspondence_scout(codelet): +@codelet('important-object-correspondence-scout') +def important_object_correspondence_scout(coderack, codelet): objectFromInitial = chooseUnmodifiedObject('relativeImportance', workspace.initial.objects) descriptors = objectFromInitial.relevantDistinguishingDescriptors() @@ -876,7 +902,8 @@ def important_object_correspondence_scout(codelet): conceptMappings, flipTargetObject, codelet) -def correspondence_strength_tester(codelet): +@codelet('correspondence-strength-tester') +def correspondence_strength_tester(coderack, codelet): correspondence = codelet.arguments[0] objectFromInitial = correspondence.objectFromInitial objectFromTarget = correspondence.objectFromTarget @@ -899,7 +926,8 @@ def correspondence_strength_tester(codelet): strength, correspondence) -def correspondence_builder(codelet): +@codelet('correspondence-builder') +def correspondence_builder(coderack, codelet): correspondence = codelet.arguments[0] objectFromInitial = correspondence.objectFromInitial objectFromTarget = correspondence.objectFromTarget diff --git a/copycat/coderack.py b/copycat/coderack.py index 8bf6867..6b44a30 100644 --- a/copycat/coderack.py +++ b/copycat/coderack.py @@ -1,9 +1,8 @@ -import re -import inspect import math import logging import random +import codeletMethods import formulas import workspaceFormulas from slipnet import slipnet @@ -24,18 +23,17 @@ def getUrgencyBin(urgency): class CodeRack(object): def __init__(self): - self.speedUpBonds = False - self.removeBreakerCodelets = False - self.removeTerracedScan = False self.pressures = CoderackPressures() self.pressures.initialisePressures() self.reset() - self.initialCodeletNames = ('bottom-up-bond-scout', - 'replacement-finder', - 'bottom-up-correspondence-scout') - self.codeletMethodsDir = None + self.initialCodeletNames = ( + 'bottom-up-bond-scout', + 'replacement-finder', + 'bottom-up-correspondence-scout', + ) self.runCodelets = {} self.postings = {} + self.getCodeletMethods() def reset(self): self.codelets = [] @@ -87,17 +85,11 @@ class CodeRack(object): self.__postBottomUpCodelets('replacement-finder') self.__postBottomUpCodelets('rule-scout') self.__postBottomUpCodelets('rule-translator') - if not self.removeBreakerCodelets: - self.__postBottomUpCodelets('breaker') + self.__postBottomUpCodelets('breaker') def __postBottomUpCodelets(self, codeletName): probability = workspaceFormulas.probabilityOfPosting(codeletName) howMany = workspaceFormulas.howManyToPost(codeletName) - #if codeletName == 'bottom-up-bond-scout': - # print 'post --> %f:%d' % (probability,howMany) - if self.speedUpBonds: - if 'bond' in codeletName or 'group' in codeletName: - howMany *= 3 urgency = 3 if codeletName == 'breaker': urgency = 1 @@ -121,7 +113,7 @@ class CodeRack(object): else: newCodelet.arguments = oldCodelet.arguments newCodelet.pressure = oldCodelet.pressure - self.tryRun(newCodelet) + self.post(newCodelet) # pylint: disable=too-many-arguments def proposeRule(self, facet, description, category, relation, oldCodelet): @@ -209,7 +201,7 @@ class CodeRack(object): return None urgencies = [] for codelet in self.codelets: - urgency = ((coderack.codeletsRun - codelet.timeStamp) * + urgency = ((self.codeletsRun - codelet.timeStamp) * (7.5 - codelet.urgency)) urgencies += [urgency] threshold = random.random() * sum(urgencies) @@ -226,17 +218,14 @@ class CodeRack(object): codelet = Codelet(name, 1, self.codeletsRun) self.post(codelet) - def tryRun(self, newCodelet): - if self.removeTerracedScan: - self.run(newCodelet) - else: - self.post(newCodelet) + def getCodeletMethods(self): + self.methods = {} + for name in dir(codeletMethods): + method = getattr(codeletMethods, name) + if getattr(method, 'is_codelet_method', False): + self.methods[method.codelet_name] = method - def getCodeletmethods(self): - import codeletMethods - - self.codeletMethodsDir = dir(codeletMethods) - knownCodeletNames = ( + assert set(self.methods.keys()) == set([ 'breaker', 'bottom-up-description-scout', 'top-down-description-scout', @@ -261,19 +250,11 @@ class CodeRack(object): 'important-object-correspondence-scout', 'correspondence-strength-tester', 'correspondence-builder', - ) - self.methods = {} - for codeletName in knownCodeletNames: - methodName = re.sub('[ -]', '_', codeletName) - if methodName not in self.codeletMethodsDir: - raise NotImplementedError( - 'Cannot find %s in codeletMethods' % methodName) - method = getattr(codeletMethods, methodName) - self.methods[methodName] = method + ]) def chooseAndRunCodelet(self): - if not len(coderack.codelets): - coderack.postInitialCodelets() + if not len(self.codelets): + self.postInitialCodelets() codelet = self.chooseCodeletToRun() if codelet: self.run(codelet) @@ -282,21 +263,6 @@ class CodeRack(object): if not self.codelets: return None - #logging.info('temperature: %f', formulas.Temperature) - #logging.info('actualTemperature: %f', formulas.actualTemperature) - #logging.info('Slipnet:') - #for node in slipnet.slipnodes: - # logging.info("\tnode %s, activation: %d, buffer: %d, depth: %s", - # node.get_name(), node.activation, node.buffer, - # node.conceptualDepth) - #logging.info('Coderack:') - #for codelet in self.codelets: - # logging.info('\t%s, %d', codelet.name, codelet.urgency) - - #from workspace import workspace - #workspace.initial.log("Initial: ") - #workspace.target.log("Target: ") - scale = (100.0 - formulas.Temperature + 10.0) / 15.0 urgsum = sum(codelet.urgency ** scale for codelet in self.codelets) threshold = random.random() * urgsum @@ -314,33 +280,12 @@ class CodeRack(object): return chosen def run(self, codelet): - methodName = re.sub('[ -]', '_', codelet.name) + methodName = codelet.name self.codeletsRun += 1 self.runCodelets[methodName] = self.runCodelets.get(methodName, 0) + 1 - - #if self.codeletsRun > 2000: - #import sys - #print "running too many codelets" - #for name,count in self.postings.iteritems(): - #print '%d:%s' % (count,name) - #raise ValueError - #else: - # print 'running %d' % self.codeletsRun - if not self.codeletMethodsDir: - self.getCodeletmethods() - #if not self.codeletMethodsDir: method = self.methods[methodName] - if not method: - raise ValueError('Found %s in codeletMethods, but cannot get it', - methodName) - if not callable(method): - raise RuntimeError('Cannot call %s()' % methodName) - args, _varargs, _varkw, _defaults = inspect.getargspec(method) try: - if 'codelet' in args: - method(codelet) - else: - method() + method(self, codelet) except AssertionError: pass