Initial addition of Python scripts

This commit is contained in:
J Alan Brogan
2012-10-26 17:35:08 +01:00
parent 90eb4a7b2a
commit 5462c033ab
27 changed files with 3794 additions and 1 deletions

View File

@ -1,4 +1,8 @@
co.py.cat
=========
An implementation of the Hofstadter copycat algorithm
An implementation of the Hofstadter [copycat](https://en.wikipedia.org/wiki/Copycat_%28software%29) algorithm
This implementation is a copycat of Scott Boland's [Java implementation](http://itee.uq.edu.au/~scottb/_Copycat/), but re-written into Python. It's not a direct translation - but based on his code. I did not carry over the GUI, as this version can more usefully be run from command line, or imported for use by other Python scripts.
In cases where I could not grok the Java implementation easily or directly I took ideas from the [LISP implementation](http://web.cecs.pdx.edu/~mm/how-to-get-copycat.html), or directly from [Melanie Mitchell](https://en.wikipedia.org/wiki/Melanie_Mitchell)'s "[Analogy-Making as Perception](http://www.amazon.com/Analogy-Making-Perception-Computer-Melanie-Mitchell/dp/0262132893/ref=tmm_hrd_title_0?ie=UTF8&qid=1351269085&sr=1-3)"

182
bond.py Normal file
View File

@ -0,0 +1,182 @@
from workspaceStructure import WorkspaceStructure
from slipnet import slipnet
from workspace import workspace
class Bond(WorkspaceStructure):
def __init__(self,source, destination, bondCategory, bondFacet, sourceDescriptor, destinationDescriptor):
WorkspaceStructure.__init__(self)
self.source = source
self.string = self.source.string
self.destination = destination
self.leftObject = self.source
self.rightObject = self.destination
self.directionCategory = slipnet.right
if self.source.leftStringPosition > self.destination.rightStringPosition:
self.leftObject = self.destination
self.rightObject = self.source
self.directionCategory = slipnet.left
self.facet = bondFacet
self.sourceDescriptor = sourceDescriptor
self.destinationDescriptor = destinationDescriptor
self.category = bondCategory
self.destinationIsOnRight = self.destination == self.rightObject
self.bidirectional = self.sourceDescriptor == self.destinationDescriptor
if self.bidirectional:
self.directionCategory = None
def flippedVersion(self):
"""
"""
return Bond(
self.destination, self.get_source(), self.category.getRelatedNode(slipnet.opposite),
self.facet, self.destinationDescriptor, self.sourceDescriptor
)
def __repr__(self):
return '<Bond: %s>' % self.__str__()
def __str__(self):
return '%s bond between %s and %s' % ( self.category.name, self.leftObject, self.rightObject)
def buildBond(self):
workspace.structures += [ self ]
self.string.bonds += [ self ]
self.category.buffer = 100.0
if self.directionCategory:
self.directionCategory.buffer = 100.0
self.leftObject.rightBond = self
self.rightObject.leftBond = self
self.leftObject.bonds += [ self ]
self.rightObject.bonds += [ self ]
def break_the_structure(self):
self.breakBond()
def breakBond(self):
if self in workspace.structures:
workspace.structures.remove(self)
if self in self.string.bonds:
self.string.bonds.remove(self)
self.leftObject.rightBond = None
self.rightObject.leftBond = None
if self in self.leftObject.bonds:
self.leftObject.bonds.remove(self)
if self in self.rightObject.bonds:
self.rightObject.bonds.remove(self)
def getIncompatibleCorrespondences(self):
# returns a list of correspondences that are incompatible with
# self bond
incompatibles = []
if self.leftObject.leftmost and self.leftObject.correspondence:
correspondence = self.leftObject.correspondence
if self.string == workspace.initial:
objekt = self.leftObject.correspondence.objectFromTarget
else:
objekt = self.leftObject.correspondence.objectFromInitial
if objekt.leftmost and objekt.rightBond:
if objekt.rightBond.directionCategory and objekt.rightBond.directionCategory != self.directionCategory:
incompatibles += [ correspondence ]
if self.rightObject.rightmost and self.rightObject.correspondence:
correspondence = self.rightObject.correspondence
if self.string == workspace.initial:
objekt = self.rightObject.correspondence.objectFromTarget
else:
objekt = self.rightObject.correspondence.objectFromInitial
if objekt.rightmost and objekt.leftBond:
if objekt.leftBond.directionCategory and objekt.leftBond.directionCategory != self.directionCategory:
incompatibles += [ correspondence ]
return incompatibles
def updateInternalStrength(self):
# bonds between objects of same type(ie. letter or group) are
# stronger than bonds between different types
sourceGap = self.get_source().leftStringPosition != self.get_source().rightStringPosition
destinationGap = self.destination.leftStringPosition != self.destination.rightStringPosition
if sourceGap == destinationGap:
memberCompatibility = 1.0
else:
memberCompatibility = 0.7
# letter category bonds are stronger
if self.facet == slipnet.letterCategory:
facetFactor = 1.0
else:
facetFactor = 0.7
strength = min(100.0,memberCompatibility * facetFactor * self.category.bondDegreeOfAssociation())
self.internalStrength = strength
def updateExternalStrength(self):
self.externalStrength = 0.0
supporters = self.numberOfLocalSupportingBonds()
if supporters > 0.0:
density = self.localDensity() / 100.0
density = density ** 0.5 * 100.0
supportFactor = 0.6 ** (1.0 / supporters ** 3)
supportFactor = max(1.0,supportFactor)
strength = supportFactor * density
self.externalStrength = strength
def numberOfLocalSupportingBonds(self):
return len([ b for b in self.string.bonds if b.string == self.get_source().string and
self.leftObject.letterDistance(b.leftObject) != 0 and
self.rightObject.letterDistance(b.rightObject) != 0 and
self.category == b.category and
self.directionCategory == b.directionCategory ])
def sameCategories(self,other):
return self.category == other.category and self.directionCategory == other.directionCategory
def myEnds(self,object1,object2):
if self.get_source() == object1 and self.destination == object2:
return True
return self.get_source() == object2 and self.destination == object1
def localDensity(self):
# returns a rough measure of the density in the string
# of the same bond-category and the direction-category of
# the given bond
slotSum = supportSum = 0.0
for object1 in workspace.objects:
if object1.string == self.string:
for object2 in workspace.objects:
if object1.beside(object2):
slotSum += 1.0
for bond in self.string.bonds:
if bond != self and self.sameCategories(bond) and self.myEnds(object1,object2):
supportSum += 1.0
if slotSum == 0.0:
return 0.0
return 100.0 * supportSum / slotSum
def sameNeighbours(self,other):
if self.leftObject == other.leftObject:
return True
return self.rightObject == other.rightObject
def getIncompatibleBonds(self):
return [ b for b in self.string.bonds if self.sameNeighbours(b) ]
def get_source(self):
return self.source
def set_source(self, value):
self.source = value
def possibleGroupBonds(bondCategory, directionCategory, bondFacet, bonds):
result = []
for bond in bonds:
if bond.category == bondCategory and bond.directionCategory == directionCategory:
result += [ bond ]
else:
# a modified bond might be made
if bondCategory == slipnet.sameness:
return None # a different bond cannot be made here
if bond.category == bondCategory or bond.directionCategory == directionCategory:
return None # a different bond cannot be made here
if bond.category == slipnet.sameness:
return None
bond = Bond(bond.destination, bond.get_source(), bondCategory, bondFacet, bond.destinationDescriptor, bond.sourceDescriptor)
result += [ bond ]
return result

10
codelet.py Normal file
View File

@ -0,0 +1,10 @@
class Codelet(object):
def __init__(self, name, urgency, timestamp):
self.name = name
self.urgency = urgency
self.arguments = []
self.pressure = None
self.timeStamp = timestamp
def __repr__(self):
return '<Codelet: %s>' % self.name

802
codeletMethods.py Normal file
View File

@ -0,0 +1,802 @@
#import utils
from coderack import coderack
from workspaceObject import WorkspaceObject
from letter import Letter
from replacement import Replacement
from formulas import *
from workspaceFormulas import *
from group import Group
from bond import Bond, possibleGroupBonds
from correspondence import Correspondence
# some methods common to the codelets
def __showWhichStringObjectIsFrom(structure):
if not structure:
return
whence = 'other'
if isinstance(structure,WorkspaceObject):
whence='target'
if structure.string == workspace.initial:
whence='initial'
print 'object chosen = %s from %s string' % ( structure, whence )
def __getScoutSource(slipnode,relevanceMethod,typeName):
initialRelevance = relevanceMethod(workspace.initial,slipnode)
targetRelevance = relevanceMethod(workspace.target,slipnode)
initialUnhappiness = workspace.initial.intraStringUnhappiness
targetUnhappiness = workspace.target.intraStringUnhappiness
logging.info('initial : relevance = %d, unhappiness=%d' % (initialRelevance,int(initialUnhappiness)) )
logging.info('target : relevance = %d, unhappiness=%d' % (targetRelevance,int(targetUnhappiness)) )
string = workspace.initial
if utils.random() * (initialRelevance + initialUnhappiness+targetRelevance+targetUnhappiness) > (initialRelevance + initialUnhappiness):
string = workspace.target
logging.info('target string selected: %s for %s' % (workspace.target,typeName))
else:
logging.info('initial string selected: %s for %s' % (workspace.initial,typeName))
source = chooseUnmodifiedObject('intraStringSalience',string.objects)
return source
def __getBondFacet(source,destination):
bondFacet = chooseBondFacet(source,destination)
assert bondFacet
return bondFacet
def __getDescriptors(bondFacet,source,destination):
sourceDescriptor = source.getDescriptor(bondFacet)
destinationDescriptor = destination.getDescriptor(bondFacet)
assert sourceDescriptor and destinationDescriptor
return sourceDescriptor, destinationDescriptor
def __allOppositeMappings(mappings):
return len([ m for m in mappings if m.label != slipnet.opposite ]) == 0
def __structureVsStructure(structure1,weight1,structure2,weight2):
structure1.updateStrength()
structure2.updateStrength()
weightedStrength1 = temperatureAdjustedValue(structure1.totalStrength * weight1)
weightedStrength2 = temperatureAdjustedValue(structure2.totalStrength * weight2)
rhs = (weightedStrength1 + weightedStrength2) * utils.random()
logging.info('%d > %d' % (weightedStrength1,rhs))
return weightedStrength1 > rhs
def __fightItOut(structure, structureWeight, incompatibles, incompatibleWeight):
if not (incompatibles and len(incompatibles)):
return True
for incompatible in incompatibles:
if not __structureVsStructure(structure, structureWeight, incompatible, incompatibleWeight):
logging.info('lost fight with %s' % incompatible)
return False
logging.info('won fight with %s' % incompatible)
return True
def __fightIncompatibles(incompatibles,structure,name,structureWeight,incompatibleWeight):
if len(incompatibles):
if __fightItOut(structure,structureWeight,incompatibles,incompatibleWeight):
logging.info('broke the %s' % name)
return True
logging.info('failed to break %s: Fizzle' % name)
return False
logging.info('no incompatible %s' % name)
return True
def __slippability(conceptMappings):
for mapping in conceptMappings:
slippiness = mapping.slipability() / 100.0
probabilityOfSlippage = temperatureAdjustedProbability(slippiness)
if formulas.coinFlip(probabilityOfSlippage):
return True
return False
# start the actual codelets
def breaker():
probabilityOfFizzle = (100.0-Temperature)/100.0
assert not coinFlip(probabilityOfFizzle)
# choose a structure at random
structures = [ s for s in workspace.structures if
isinstance(s,Group) or
isinstance(s,Bond) or
isinstance(s,Correspondence) ]
assert len(structures)
structure = utils.choice(structures)
__showWhichStringObjectIsFrom(structure)
breakObjects = [ structure ]
if isinstance(structure,Bond):
if structure.source.group and structure.source.group == structure.destination.group:
breakObjects += [ structure.source.group ]
# try to break all objects
for structure in breakObjects:
breakProbability = temperatureAdjustedProbability(structure.totalStrength/100.0)
if coinFlip(breakProbability):
return
for structure in breakObjects:
structure.break_the_structure()
def bottom_up_description_scout(codelet):
chosenObject = chooseUnmodifiedObject('totalSalience',workspace.objects)
assert chosenObject
__showWhichStringObjectIsFrom(chosenObject)
description = chooseRelevantDescriptionByActivation(chosenObject)
assert description
sliplinks = similarPropertyLinks(description.descriptor)
assert sliplinks and len(sliplinks)
values = [ sliplink.degreeOfAssociation() * sliplink.destination.activation for sliplink in sliplinks ]
i = selectListPosition(values)
chosen = sliplinks[ i ]
chosenProperty = chosen.destination
coderack.proposeDescription(chosenObject,chosenProperty.category(),chosenProperty,codelet)
def top_down_description_scout(codelet):
descriptionType = codelet.arguments[0]
chosenObject = chooseUnmodifiedObject('totalSalience',workspace.objects)
assert chosenObject
__showWhichStringObjectIsFrom(chosenObject)
descriptions = chosenObject.getPossibleDescriptions(descriptionType)
assert descriptions and len(descriptions)
values = [ n.activation for n in descriptions ]
i = selectListPosition(values)
chosenProperty = descriptions[ i ]
coderack.proposeDescription(chosenObject,chosenProperty.category(), chosenProperty,codelet)
def description_strength_tester(codelet):
description = codelet.arguments[0]
description.descriptor.buffer = 100.0
description.updateStrength()
strength = description.totalStrength
probability = temperatureAdjustedProbability(strength/100.0)
assert formulas.coinFlip(probability)
coderack.newCodelet('description-builder',codelet,strength)
def description_builder(codelet):
description = codelet.arguments[0]
assert description.object in workspace.objects
if description.object.hasDescription(description.descriptor):
description.descriptionType.buffer = 100.0
description.descriptor.buffer = 100.0
else:
description.build()
def bottom_up_bond_scout(codelet):
source = chooseUnmodifiedObject('intraStringSalience',workspace.objects)
__showWhichStringObjectIsFrom(source)
destination = chooseNeighbour(source)
assert destination
logging.info('destination: %s' % destination)
bondFacet = __getBondFacet(source,destination)
logging.info('chosen bond facet: %s' % bondFacet.get_name())
logging.info('Source: %s, destination: %s' % (source,destination))
sourceDescriptor, destinationDescriptor = __getDescriptors(bondFacet,source,destination)
logging.info("source descriptor: " + sourceDescriptor.name.upper())
logging.info("destination descriptior: " + destinationDescriptor.name.upper())
category = sourceDescriptor.getBondCategory(destinationDescriptor)
assert category
if category == slipnet.identity:
category = slipnet.sameness
logging.info('proposing %s bond ' % category.name)
coderack.proposeBond(source,destination,category,bondFacet,sourceDescriptor,destinationDescriptor,codelet)
def rule_scout(codelet):
assert workspace.numberOfUnreplacedObjects() == 0
changedObjects = [ o for o in workspace.initial.objects if o.changed ]
#assert len(changedObjects) < 2
# if there are no changed objects, propose a rule with no changes
if not changedObjects:
return coderack.proposeRule(None,None,None,None,codelet)
changed = changedObjects[-1]
# generate a list of distinguishing descriptions for the first object
# ie. string-position (leftmost,rightmost,middle or whole) or letter category
# if it is the only one of its type in the string
objectList = []
position = changed.getDescriptor(slipnet.stringPositionCategory)
if position:
objectList += [ position ]
letter = changed.getDescriptor(slipnet.letterCategory)
otherObjectsOfSameLetter = [ o for o in workspace.initial.objects if not o != changed and o.getDescriptionType(letter) ]
if not len(otherObjectsOfSameLetter): # then the letter is a distinguishing feature
objectList += [ letter ]
# if this object corresponds to another object in the workspace
# objectList = the union of this and the distingushing descriptors
if changed.correspondence:
targetObject = changed.correspondence.objectFromTarget
newList = []
slippages = workspace.slippages()
for node in objectList:
node = node.applySlippages(slippages)
if targetObject.hasDescription(node) and targetObject.distinguishingDescriptor(node):
newList += [ node ]
objectList = newList # XXX surely this should be += ("the union of this and the distinguishing descriptors")
assert objectList and len(objectList)
# use conceptual depth to choose a description
valueList = []
for node in objectList:
depth = node.conceptualDepth
value = temperatureAdjustedValue(depth)
valueList += [ value ]
i = selectListPosition(valueList)
descriptor = objectList[ i ]
# choose the relation (change the letmost object to..xxxx) i.e. "successor" or "d"
objectList = []
if changed.replacement.relation:
objectList += [ changed.replacement.relation ]
objectList += [ changed.replacement.objectFromModified.getDescriptor(slipnet.letterCategory) ]
# use conceptual depth to choose a relation
valueList = []
for node in objectList:
depth = node.conceptualDepth
value = temperatureAdjustedValue(depth)
valueList += [ value ]
i = selectListPosition(valueList)
relation = objectList[ i ]
coderack.proposeRule(slipnet.letterCategory,descriptor,slipnet.letter,relation,codelet)
def rule_strength_tester(codelet):
rule = codelet.arguments[0]
rule.updateStrength()
probability = temperatureAdjustedProbability(rule.totalStrength / 100.0)
assert utils.random() <= probability
coderack.newCodelet('rule-builder',codelet,rule.totalStrength,rule)
def replacement_finder():
# choose random letter in initial string
letters = [ o for o in workspace.initial.objects if isinstance(o,Letter) ]
letterOfInitialString = utils.choice(letters)
logging.info('selected letter in initial string = %s' % letterOfInitialString)
if letterOfInitialString.replacement:
logging.info("Replacement already found for %s, so fizzling" % letterOfInitialString)
return
position = letterOfInitialString.leftStringPosition
moreLetters = [ o for o in workspace.modified.objects if isinstance(o,Letter) and o.leftStringPosition == position ]
letterOfModifiedString = moreLetters and moreLetters[0] or None
assert letterOfModifiedString
position -= 1
initialAscii = ord(workspace.initialString[position])
modifiedAscii = ord(workspace.modifiedString[position])
diff = initialAscii - modifiedAscii
if abs(diff) < 2:
relations = { 0:slipnet.sameness, -1:slipnet.successor, 1:slipnet.predecessor }
relation = relations[diff]
logging.info('Relation found: %s' % relation.name)
else:
relation = None
logging.info('no relation found')
letterOfInitialString.replacement = Replacement(letterOfInitialString,letterOfModifiedString,relation)
if relation != slipnet.sameness:
letterOfInitialString.changed = True
workspace.changedObject = letterOfInitialString
logging.info('building replacement')
def top_down_bond_scout__category(codelet):
logging.info('top_down_bond_scout__category')
category = codelet.arguments[0]
source = __getScoutSource(category,localBondCategoryRelevance,'bond')
destination = chooseNeighbour(source)
logging.info('source: %s, destination: %s' % (source,destination))
assert destination
bondFacet = __getBondFacet(source,destination)
sourceDescriptor, destinationDescriptor = __getDescriptors(bondFacet,source,destination)
forwardBond = sourceDescriptor.getBondCategory(destinationDescriptor)
if forwardBond == slipnet.identity:
forwardBond = slipnet.sameness
backwardBond = slipnet.sameness
else:
backwardBond = destinationDescriptor.getBondCategory(sourceDescriptor)
assert category == forwardBond or category == backwardBond
if category == forwardBond:
coderack.proposeBond(source,destination,category,bondFacet,sourceDescriptor, destinationDescriptor,codelet)
else:
coderack.proposeBond(destination,source,category,bondFacet,destinationDescriptor,sourceDescriptor,codelet)
def top_down_bond_scout__direction(codelet):
direction = codelet.arguments[0]
source = __getScoutSource(direction,localDirectionCategoryRelevance,'bond')
destination = chooseDirectedNeighbor(source,direction)
assert destination
logging.info('to object: %s' % destination)
bondFacet = __getBondFacet(source,destination)
sourceDescriptor, destinationDescriptor = __getDescriptors(bondFacet,source,destination)
category = sourceDescriptor.getBondCategory(destinationDescriptor)
assert category
if category == slipnet.identity:
category = slipnet.sameness
coderack.proposeBond(source,destination,category,bondFacet,sourceDescriptor, destinationDescriptor,codelet)
def bond_strength_tester(codelet):
bond = codelet.arguments[0]
__showWhichStringObjectIsFrom(bond)
bond.updateStrength()
strength = bond.totalStrength
probability = temperatureAdjustedProbability(strength/100.0)
logging.info('bond strength = %d for %s' % (strength,bond))
assert formulas.coinFlip(probability)
bond.facet.buffer = 100.0
bond.sourceDescriptor.buffer = 100.0
bond.destinationDescriptor.buffer = 100.0
logging.info("succeeded: posting bond-builder")
coderack.newCodelet('bond-builder',codelet,strength)
def bond_builder(codelet):
bond = codelet.arguments[0]
__showWhichStringObjectIsFrom(bond)
bond.updateStrength()
assert (bond.source in workspace.objects or bond.destination in workspace.objects)
for stringBond in bond.string.bonds:
if bond.sameNeighbours(stringBond) and bond.sameCategories(stringBond):
if bond.directionCategory:
bond.directionCategory.buffer = 100.0
bond.category.buffer = 100.0
logging.info('already exists: activate descriptors & Fizzle')
return
incompatibleBonds = bond.getIncompatibleBonds()
logging.info('number of incompatibleBonds: %d' % len(incompatibleBonds))
if len(incompatibleBonds):
logging.info('%s' % incompatibleBonds[0])
assert __fightIncompatibles(incompatibleBonds,bond,'bonds',1.0,1.0)
incompatibleGroups = bond.source.getCommonGroups(bond.destination)
assert __fightIncompatibles(incompatibleGroups,bond,'groups',1.0,1.0)
# fight all incompatible correspondences
incompatibleCorrespondences = []
if bond.leftObject.leftmost or bond.rightObject.rightmost:
if bond.directionCategory:
incompatibleCorrespondences = bond.getIncompatibleCorrespondences()
if incompatibleCorrespondences:
logging.info("trying to break incompatible correspondences")
assert __fightItOut(bond,2.0,incompatibleCorrespondences,3.0)
#assert __fightIncompatibles(incompatibleCorrespondences,bond,'correspondences',2.0,3.0)
for incompatible in incompatibleBonds:
incompatible.break_the_structure()
for incompatible in incompatibleGroups:
incompatible.break_the_structure()
for incompatible in incompatibleCorrespondences:
incompatible.break_the_structure()
logging.info('building bond %s' % bond)
bond.buildBond()
def top_down_group_scout__category(codelet):
groupCategory = codelet.arguments[0]
category = groupCategory.getRelatedNode(slipnet.bondCategory)
assert category
source = __getScoutSource(category,localBondCategoryRelevance,'group')
assert source and not source.spansString()
if source.leftmost:
direction = slipnet.right
elif source.rightmost:
direction = slipnet.left
else:
activations = [ slipnet.left.activation ]
activations += [ slipnet.right.activation ]
if not selectListPosition(activations):
direction = slipnet.left
else:
direction = slipnet.right
if direction == slipnet.left:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond or firstBond.category != category:
# check the other side of object
if direction == slipnet.right:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond or firstBond.category != category:
if category == slipnet.sameness and isinstance(source,Letter):
group = Group(source.string,slipnet.samenessGroup, None,slipnet.letterCategory, [ source ], [])
probability = group.singleLetterGroupProbability()
assert utils.random() >= probability
coderack.proposeSingleLetterGroup( source, codelet)
return
direction = firstBond.directionCategory
search = True
bondFacet = None
# find leftmost object in group with these bonds
while search:
search = False
if source.leftBond:
if source.leftBond.category == category:
if not source.leftBond.directionCategory or source.leftBond.directionCategory == direction:
if not bondFacet or bondFacet == source.leftBond.facet:
bondFacet = source.leftBond.facet
direction = source.leftBond.directionCategory
source = source.leftBond.leftObject
search = True
# find rightmost object in group with these bonds
search = True
destination = source
while search:
search = False
if destination.rightBond:
if destination.rightBond.category == category:
if not destination.rightBond.directionCategory or destination.rightBond.directionCategory == direction:
if not bondFacet or bondFacet == destination.rightBond.facet:
bondFacet = destination.rightBond.facet
direction = source.rightBond.directionCategory
destination = destination.rightBond.rightObject
search = True
assert destination != source
objects = [ source ]
bonds = []
while source != destination:
bonds += [ source.rightBond ]
objects += [ source.rightBond.rightObject ]
source = source.rightBond.rightObject
coderack.proposeGroup(objects,bonds,groupCategory,direction,bondFacet,codelet)
def top_down_group_scout__direction(codelet):
direction = codelet.arguments[0]
source = __getScoutSource(direction,localDirectionCategoryRelevance,'direction')
logging.info('source chosen = %s' % source)
assert not source.spansString()
if source.leftmost :
mydirection = slipnet.right
elif source.rightmost:
mydirection = slipnet.left
else:
activations = [ slipnet.left.activation ]
activations += [ slipnet.right.activation ]
if not selectListPosition(activations):
mydirection = slipnet.left
else:
mydirection = slipnet.right
if mydirection == slipnet.left:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond:
logging.info('no firstBond')
else:
logging.info('firstBond: %s' % firstBond)
if firstBond and not firstBond.directionCategory:
direction = None
if not firstBond or firstBond.directionCategory != direction:
if mydirection == slipnet.right:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond:
logging.info('no firstBond2')
else:
logging.info('firstBond2: %s' % firstBond)
if firstBond and not firstBond.directionCategory:
direction = None
assert firstBond and firstBond.directionCategory == direction
logging.info('possible group: %s' % firstBond)
category = firstBond.category
assert category
groupCategory = category.getRelatedNode(slipnet.groupCategory)
logging.info('trying from %s to %s' % (source,category.name) )
bondFacet = None
# find leftmost object in group with these bonds
search = True
while search:
search = False
if source.leftBond:
if source.leftBond.category == category:
if not source.leftBond.directionCategory or source.leftBond.directionCategory == direction:
if not bondFacet or bondFacet == source.leftBond.facet:
bondFacet = source.leftBond.facet
direction = source.leftBond.directionCategory
source = source.leftBond.leftObject
search = True
destination = source
search = True
while search:
search = False
if destination.rightBond:
if destination.rightBond.category == category:
if not destination.rightBond.directionCategory or destination.rightBond.directionCategory == direction:
if not bondFacet or bondFacet == destination.rightBond.facet:
bondFacet = destination.rightBond.facet
direction = source.rightBond.directionCategory
destination = destination.rightBond.rightObject
search = True
assert destination != source
logging.info('proposing group from %s to %s' % (source,destination) )
objects = [ source ]
bonds = []
while source != destination:
bonds += [ source.rightBond ]
objects += [ source.rightBond.rightObject ]
source = source.rightBond.rightObject
coderack.proposeGroup(objects,bonds,groupCategory,direction,bondFacet,codelet)
#noinspection PyStringFormat
def group_scout__whole_string(codelet):
string = workspace.initial
if utils.random() > 0.5:
string = workspace.target
logging.info('target string selected: %s' % workspace.target )
else:
logging.info('initial string selected: %s' % workspace.initial )
# find leftmost object & the highest group to which it belongs
leftmost = None
for objekt in string.objects:
if objekt.leftmost:
leftmost = objekt
while leftmost.group and leftmost.group.bondCategory == slipnet.sameness:
leftmost = leftmost.group
if leftmost.spansString():
# the object already spans the string - propose this object
group = leftmost
coderack.proposeGroup(group.objectList, group.bondList,group.groupCategory,group.directionCategory, group.facet,codelet)
return
bonds = []
objects = [ leftmost ]
while leftmost.rightBond:
bonds += [ leftmost.rightBond ]
leftmost = leftmost.rightBond.rightObject
objects += [ leftmost ]
assert leftmost.rightmost
# choose a random bond from list
chosenBond = utils.choice(bonds)
category = chosenBond.category
directionCategory = chosenBond.directionCategory
bondFacet = chosenBond.facet
bonds = possibleGroupBonds(category, directionCategory, bondFacet, bonds)
assert bonds
groupCategory = category.getRelatedNode(slipnet.groupCategory)
coderack.proposeGroup(objects,bonds,groupCategory,directionCategory,bondFacet,codelet)
def group_strength_tester(codelet):
# update strength value of the group
group = codelet.arguments[0]
__showWhichStringObjectIsFrom(group)
group.updateStrength()
strength = group.totalStrength
probability = temperatureAdjustedProbability(strength/100.0)
assert utils.random() <= probability
# it is strong enough - post builder & activate nodes
group.groupCategory.getRelatedNode(slipnet.bondCategory).buffer = 100.0
if group.directionCategory:
group.directionCategory.buffer=100.0
coderack.newCodelet('group-builder',codelet,strength)
def group_builder(codelet):
# update strength value of the group
group = codelet.arguments[0]
#print '%s' % group
__showWhichStringObjectIsFrom(group)
equivalent = group.string.equivalentGroup(group)
if equivalent :
logging.info('already exists...activate descriptors & fizzle')
group.activateDescriptions()
equivalent.addDescriptions(group.descriptions)
return
# check to see if all objects are still there
for o in group.objectList:
assert o in workspace.objects
# check to see if bonds are there of the same direction
incompatibleBonds = [] # incompatible bond list
if len(group.objectList) > 1:
previous = group.objectList[0]
for objekt in group.objectList[1:]:
#print 770
leftBond = objekt.leftBond
if leftBond:
lefty = leftBond.leftObject
if lefty != previous or leftBond.directionCategory != group.directionCategory:
incompatibleBonds += [ leftBond ]
previous = objekt
next = group.objectList[-1]
for objekt in reversed(group.objectList[:-1]):
rightBond = objekt.rightBond
if rightBond:
righty = rightBond.rightObject
if righty != next or rightBond.directionCategory != group.directionCategory:
incompatibleBonds += [ rightBond ]
next = objekt
# if incompatible bonds exist - fight
group.updateStrength()
assert __fightIncompatibles(incompatibleBonds,group,'bonds',1.0,1.0)
# fight incompatible groups
# fight all groups containing these objects
incompatibleGroups = group.getIncompatibleGroups()
assert __fightIncompatibles(incompatibleGroups,group,'Groups',1.0,1.0)
for incompatible in incompatibleBonds:
incompatible.break_the_structure()
# create new bonds
group.bondList = []
for i in range(1,len(group.objectList)):
#print 803
object1 = group.objectList[i - 1]
object2 = group.objectList[i]
if not object1.rightBond:
if group.directionCategory == slipnet.right:
source = object1
destination = object2
else:
source = object2
destination = object1
category = group.groupCategory.getRelatedNode(slipnet.bondCategory)
facet = group.facet
newBond = Bond(source,destination,category,facet,source.getDescriptor(facet),destination.getDescriptor(facet))
newBond.buildBond()
group.bondList += [ object1.rightBond ]
for incompatible in incompatibleGroups:
incompatible.break_the_structure()
group.buildGroup()
group.activateDescriptions()
logging.info('building group')
def rule_builder(codelet):
rule = codelet.arguments[0]
if rule.ruleEqual(workspace.rule):
rule.activateRuleDescriptions()
return
rule.updateStrength()
assert rule.totalStrength
# fight against other rules
if workspace.rule:
assert __structureVsStructure(rule,1.0,workspace.rule,1.0)
workspace.buildRule(rule)
def __getCutOff(density):
if density > 0.8:
distribution = [ 5.0,150.0,5.0,2.0,1.0,1.0,1.0,1.0,1.0,1.0 ]
elif density > 0.6:
distribution = [ 2.0,5.0,150.0,5.0,2.0,1.0,1.0,1.0,1.0,1.0 ]
elif density > 0.4:
distribution = [ 1.0,2.0,5.0,150.0,5.0,2.0,1.0,1.0,1.0,1.0 ]
elif density > 0.2:
distribution = [ 1.0,1.0,2.0,5.0,150.0,5.0,2.0,1.0,1.0,1.0 ]
else:
distribution = [ 1.0,1.0,1.0,2.0,5.0,150.0,5.0,2.0,1.0,1.0 ]
stop = sum(distribution) * utils.random()
total = 0.0
for i in range(0,len(distribution)):
total += distribution[i]
if total >= stop:
return i + 1
return len(distribution)
def rule_translator():
assert workspace.rule
if len(workspace.initial) == 1 and len(workspace.target) == 1:
bondDensity = 1.0
else:
numberOfBonds = len(workspace.initial.bonds) + len(workspace.target.bonds)
nearlyTotalLength = len(workspace.initial) + len(workspace.target) - 2
bondDensity = numberOfBonds / nearlyTotalLength
if bondDensity>1.0:
bondDensity = 1.0
cutoff = __getCutOff(bondDensity) * 10.0
assert cutoff >= formulas.actualTemperature
if workspace.rule.buildTranslatedRule():
workspace.foundAnswer = True
else:
temperature.clampTime = coderack.codeletsRun + 100
temperature.clamped = True
formulas.Temperature = 100.0
def bottom_up_correspondence_scout(codelet):
objectFromInitial = chooseUnmodifiedObject('interStringSalience',workspace.initial.objects)
objectFromTarget = chooseUnmodifiedObject('interStringSalience',workspace.target.objects)
assert objectFromInitial.spansString() == objectFromTarget.spansString()
# get the posible concept mappings
conceptMappings = getMappings( objectFromInitial, objectFromTarget, objectFromInitial.relevantDescriptions(), objectFromTarget.relevantDescriptions())
assert conceptMappings and __slippability(conceptMappings)
#find out if any are distinguishing
distinguishingMappings = [ m for m in conceptMappings if m.distinguishing() ]
assert distinguishingMappings
# if both objects span the strings, check to see if the
# string description needs to be flipped
oppositeMappings = [ m for m in distinguishingMappings
if m.initialDescriptionType == slipnet.stringPositionCategory and
m.initialDescriptionType != slipnet.bondFacet ]
initialDescriptionTypes = [ m.initialDescriptionType for m in oppositeMappings ]
flipTargetObject = False
if objectFromInitial.spansString() and objectFromTarget.spansString() and slipnet.directionCategory in initialDescriptionTypes and __allOppositeMappings(oppositeMappings) and slipnet.opposite.activation != 100.0:
objectFromTarget = objectFromTarget.flippedVersion()
conceptMappings = getMappings( objectFromInitial, objectFromTarget, objectFromInitial.relevantDescriptions(), objectFromTarget.relevantDescriptions())
flipTargetObject = True
coderack.proposeCorrespondence(objectFromInitial,objectFromTarget,conceptMappings,flipTargetObject,codelet)
def important_object_correspondence_scout(codelet):
objectFromInitial = chooseUnmodifiedObject('relativeImportance',workspace.initial.objects)
descriptors = objectFromInitial.relevantDistinguishingDescriptors()
slipnode = chooseSlipnodeByConceptualDepth(descriptors)
assert slipnode
initialDescriptor = slipnode
for mapping in workspace.slippages():
if mapping.initialDescriptor == slipnode:
initialDescriptor = mapping.targetDescriptor
targetCandidates = []
for objekt in workspace.target.objects:
for description in objekt.relevantDescriptions():
if description.descriptor == initialDescriptor:
targetCandidates += [ objekt ]
assert targetCandidates
objectFromTarget = chooseUnmodifiedObject('interStringSalience',targetCandidates)
assert objectFromInitial.spansString() == objectFromTarget.spansString()
# get the posible concept mappings
conceptMappings = getMappings( objectFromInitial, objectFromTarget, objectFromInitial.relevantDescriptions(), objectFromTarget.relevantDescriptions())
assert conceptMappings and __slippability(conceptMappings)
#find out if any are distinguishing
distinguishingMappings = [ m for m in conceptMappings if m.distinguishing() ]
assert distinguishingMappings
# if both objects span the strings, check to see if the
# string description needs to be flipped
oppositeMappings = [ m for m in distinguishingMappings if m.initialDescriptionType == slipnet.stringPositionCategory and m.initialDescriptionType != slipnet.bondFacet ]
initialDescriptionTypes = [ m.initialDescriptionType for m in oppositeMappings ]
flipTargetObject = False
if objectFromInitial.spansString() and objectFromTarget.spansString() and slipnet.directionCategory in initialDescriptionTypes and __allOppositeMappings(oppositeMappings) and slipnet.opposite.activation != 100.0:
objectFromTarget = objectFromTarget.flippedVersion()
conceptMappings = getMappings( objectFromInitial, objectFromTarget,objectFromInitial.relevantDescriptions(), objectFromTarget.relevantDescriptions())
flipTargetObject = True
coderack.proposeCorrespondence(objectFromInitial,objectFromTarget,conceptMappings,flipTargetObject,codelet)
def correspondence_strength_tester(codelet):
correspondence = codelet.arguments[0]
objectFromInitial = correspondence.objectFromInitial
objectFromTarget = correspondence.objectFromTarget
assert objectFromInitial in workspace.objects and (objectFromTarget in workspace.objects or correspondence.flipTargetObject and not workspace.target.equivalentGroup(objectFromTarget.flipped_version()))
correspondence.updateStrength()
strength = correspondence.totalStrength
probability = temperatureAdjustedProbability(strength/100.0)
assert utils.random() <= probability
# activate some concepts
for mapping in correspondence.conceptMappings:
mapping.initialDescriptionType.buffer = 100.0
mapping.initialDescriptor.buffer = 100.0
mapping.targetDescriptionType.buffer = 100.0
mapping.targetDescriptor.buffer = 100.0
coderack.newCodelet('correspondence-builder',codelet,strength,correspondence)
def correspondence_builder(codelet):
correspondence = codelet.arguments[0]
objectFromInitial = correspondence.objectFromInitial
objectFromTarget = correspondence.objectFromTarget
wantFlip = correspondence.flipTargetObject
if wantFlip:
flipper = objectFromTarget.flippedVersion()
targetNotFlipped = not workspace.target.equivalentGroup(flipper)
else:
targetNotFlipped = False
initialInObjects = objectFromInitial in workspace.objects
targetInObjects = objectFromTarget in workspace.objects
assert (initialInObjects or (not targetInObjects and (not (wantFlip and targetNotFlipped))))
if correspondence.reflexive():
# if the correspondence exists, activate concept mappings
# and add new ones to the existing corr.
existing = correspondence.objectFromInitial.correspondence
for mapping in correspondence.conceptMappings:
if mapping.label:
mapping.label.buffer = 100.0
if not mapping.isContainedBy(existing.conceptMappings):
existing.conceptMappings += [ mapping ]
return
incompatibleCorrespondences = correspondence.getIncompatibleCorrespondences()
# fight against all correspondences
if incompatibleCorrespondences:
correspondenceSpans = correspondence.objectFromInitial.letterSpan() + correspondence.objectFromTarget.letterSpan()
for incompatible in incompatibleCorrespondences:
incompatibleSpans = incompatible.objectFromInitial.letterSpan() + incompatible.objectFromTarget.letterSpan()
assert __structureVsStructure(correspondence,correspondenceSpans,incompatible,incompatibleSpans)
incompatibleBond = None
incompatibleGroup = None
# if there is an incompatible bond then fight against it
if correspondence.objectFromInitial.leftmost or correspondence.objectFromInitial.rightmost and correspondence.objectFromTarget.leftmost or correspondence.objectFromTarget.rightmost:
# search for the incompatible bond
incompatibleBond = correspondence.getIncompatibleBond()
if incompatibleBond:
# bond found - fight against it
assert __structureVsStructure(correspondence,3.0,incompatibleBond,2.0)
# won against incompatible bond
incompatibleGroup = correspondence.objectFromTarget.group
if incompatibleGroup:
assert __structureVsStructure(correspondence,1.0,incompatibleGroup,1.0)
# if there is an incompatible rule, fight against it
incompatibleRule = None
if workspace.rule and workspace.rule.incompatibleRuleCorrespondence(correspondence):
incompatibleRule = workspace.rule
assert __structureVsStructure( correspondence,1.0,incompatibleRule,1.0)
for incompatible in incompatibleCorrespondences:
incompatible.break_the_structure()
# break incompatible group and bond if they exist
if incompatibleBond:
incompatibleBond.break_the_structure()
if incompatibleGroup:
incompatibleGroup.break_the_structure()
if incompatibleRule:
workspace.breakRule()
correspondence.buildCorrespondence()

338
coderack.py Normal file
View File

@ -0,0 +1,338 @@
import re, inspect, math, logging
import utils
import formulas
import workspaceFormulas
from slipnet import slipnet
from codelet import Codelet
from coderackPressure import CoderackPressures
NUMBER_OF_BINS = 7
MAX_NUMBER_OF_CODELETS = 100
codeletsUsed = {}
class CodeRack(object):
def __init__(self):
#logging.debug('coderack.__init__()')
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.runCodelets = {}
self.postings = {}
def reset(self):
#logging.debug('coderack.reset()')
from temperature import temperature
self.codelets = []
self.codeletsRun = 0
temperature.clamped = True
self.pressures.reset()
def updateCodelets(self):
if self.codeletsRun > 0:
self.postTopDownCodelets()
self.postBottomUpCodelets()
def getUrgencyBin(self, urgency):
bin = int(urgency) * NUMBER_OF_BINS
bin /= 100
if bin >= NUMBER_OF_BINS:
bin = NUMBER_OF_BINS - 1
return bin + 1
def post(self, codelet):
#logging.info('Posting codelet called: %s, with urgency %f' % (codelet.name,codelet.urgency))
self.postings[codelet.name] = self.postings.get(codelet.name, 0) + 1
self.pressures.addCodelet(codelet)
self.codelets += [codelet]
if len(self.codelets) > 100:
oldCodelet = self.chooseOldCodelet()
self.removeCodelet(oldCodelet)
def postTopDownCodelets(self):
for node in slipnet.slipnodes:
#logging.info('Trying slipnode: %s' % node.get_name())
if node.activation == 100.0:
#logging.info('using slipnode: %s' % node.get_name())
for codeletName in node.codelets:
probability = workspaceFormulas.probabilityOfPosting(codeletName)
howMany = workspaceFormulas.howManyToPost(codeletName)
#print '%s:%d' % (codeletName,howMany)
for unused in range(0, howMany):
if utils.random() < probability:
urgency = self.getUrgencyBin(node.activation * node.conceptualDepth / 100.0)
codelet = Codelet(codeletName, urgency, self.codeletsRun)
codelet.arguments += [node]
logging.info('Post top down: %s, with urgency: %d' % (codelet.name, urgency))
#logging.info("From slipnode %s, activation: %s, depth: %s" %(node.get_name(),node.activation,node.conceptual_depth) )
self.post(codelet)
def postBottomUpCodelets(self):
logging.info("posting bottom up codelets")
self.__postBottomUpCodelets('bottom-up-description-scout')
self.__postBottomUpCodelets('bottom-up-bond-scout')
self.__postBottomUpCodelets('group-scout--whole-string')
self.__postBottomUpCodelets('bottom-up-correspondence-scout')
self.__postBottomUpCodelets('important-object-correspondence-scout')
self.__postBottomUpCodelets('replacement-finder')
self.__postBottomUpCodelets('rule-scout')
self.__postBottomUpCodelets('rule-translator')
if not self.removeBreakerCodelets:
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
if formulas.Temperature < 25.0 and 'translator' in codeletName:
urgency = 5
for unused in range(0, howMany):
if utils.random() < probability:
codelet = Codelet(codeletName, urgency, self.codeletsRun)
self.post(codelet)
def removeCodelet(self, codelet):
self.codelets.remove(codelet)
self.pressures.removeCodelet(codelet)
def newCodelet(self, name, oldCodelet, strength, arguments=None):
#logging.debug('Posting new codelet called %s' % name)
urgency = self.getUrgencyBin(strength)
newCodelet = Codelet(name, urgency, self.codeletsRun)
if arguments:
newCodelet.arguments = [arguments]
else:
newCodelet.arguments = oldCodelet.arguments
newCodelet.pressure = oldCodelet.pressure
self.tryRun(newCodelet)
def proposeRule(self, facet, description, category, relation, oldCodelet):
"""Creates a proposed rule, and posts a rule-strength-tester codelet.
The new codelet has urgency a function of the degree of conceptual-depth of the descriptions in the rule
"""
from rule import Rule
rule = Rule(facet, description, category, relation)
rule.updateStrength()
if description and relation:
depths = description.conceptualDepth + relation.conceptualDepth
depths /= 200.0
urgency = math.sqrt(depths) * 100.0
else:
urgency = 0
self.newCodelet('rule-strength-tester', oldCodelet, urgency, rule)
def proposeCorrespondence(self, initialObject, targetObject, conceptMappings, flipTargetObject, oldCodelet):
from correspondence import Correspondence
correspondence = Correspondence(initialObject, targetObject, conceptMappings, flipTargetObject)
for mapping in conceptMappings:
mapping.initialDescriptionType.buffer = 100.0
mapping.initialDescriptor.buffer = 100.0
mapping.targetDescriptionType.buffer = 100.0
mapping.targetDescriptor.buffer = 100.0
mappings = correspondence.distinguishingConceptMappings()
urgency = sum([mapping.strength() for mapping in mappings])
numberOfMappings = len(mappings)
if urgency:
urgency /= numberOfMappings
bin = self.getUrgencyBin(urgency)
logging.info('urgency: %s, number: %d, bin: %d' % (urgency, numberOfMappings, bin))
self.newCodelet('correspondence-strength-tester', oldCodelet, urgency, correspondence)
def proposeDescription(self, objekt, descriptionType, descriptor, oldCodelet):
from description import Description
description = Description(objekt, descriptionType, descriptor)
descriptor.buffer = 100.0
urgency = descriptionType.activation
self.newCodelet('description-strength-tester', oldCodelet, urgency, description)
def proposeSingleLetterGroup(self, source, codelet):
self.proposeGroup([source], [], slipnet.samenessGroup, None, slipnet.letterCategory, codelet)
def proposeGroup(self, objects, bondList, groupCategory, directionCategory, bondFacet, oldCodelet ):
from group import Group
bondCategory = groupCategory.getRelatedNode(slipnet.bondCategory)
bondCategory.buffer = 100.0
if directionCategory:
directionCategory.buffer = 100.0
group = Group(objects[0].string, groupCategory, directionCategory, bondFacet, objects, bondList)
urgency = bondCategory.bondDegreeOfAssociation()
self.newCodelet('group-strength-tester', oldCodelet, urgency, group)
def proposeBond(self, source, destination, bondCategory, bondFacet, sourceDescriptor, destinationDescriptor, oldCodelet ):
from bond import Bond
bondFacet.buffer = 100.0
sourceDescriptor.buffer = 100.0
destinationDescriptor.buffer = 100.0
bond = Bond(source, destination, bondCategory, bondFacet, sourceDescriptor, destinationDescriptor)
urgency = bondCategory.bondDegreeOfAssociation()
self.newCodelet('bond-strength-tester', oldCodelet, urgency, bond)
def chooseOldCodelet(self):
# selects an old codelet to remove from the coderack
# more likely to select lower urgency codelets
if not len(self.codelets):
return None
urgencies = []
for codelet in self.codelets:
urgency = (coderack.codeletsRun - codelet.timeStamp) * (7.5 - codelet.urgency)
urgencies += [urgency]
threshold = utils.random() * sum(urgencies)
sumOfUrgencies = 0.0
for i in range(0, len(self.codelets)):
sumOfUrgencies += urgencies[i]
if sumOfUrgencies > threshold:
return self.codelets[i]
return self.codelets[0]
def postInitialCodelets(self):
#logging.debug('Posting initial codelets')
#logging.debug('Number of inital codelets: %d' % len(self.initialCodeletNames))
#logging.debug('Number of workspaceObjects: %d' % workspace.numberOfObjects())
for name in self.initialCodeletNames:
for unused in range(0, workspaceFormulas.numberOfObjects()):
codelet = Codelet(name, 1, self.codeletsRun)
self.post(codelet)
codelet2 = Codelet(name, 1, self.codeletsRun)
self.post(codelet2)
def tryRun(self, newCodelet):
if self.removeTerracedScan:
self.run(newCodelet)
else:
self.post(newCodelet)
def getCodeletmethods(self):
import codeletMethods
self.codeletMethodsDir = dir(codeletMethods)
knownCodeletNames = (
'breaker',
'bottom-up-description-scout',
'top-down-description-scout',
'description-strength-tester',
'description-builder',
'bottom-up-bond-scout',
'top-down-bond-scout--category',
'top-down-bond-scout--direction',
'bond-strength-tester',
'bond-builder',
'top-down-group-scout--category',
'top-down-group-scout--direction',
'group-scout--whole-string',
'group-strength-tester',
'group-builder',
'replacement-finder',
'rule-scout',
'rule-strength-tester',
'rule-builder',
'rule-translator',
'bottom-up-correspondence-scout',
'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()
codelet = self.chooseCodeletToRun()
if codelet:
self.run(codelet)
def chooseCodeletToRun(self):
if not self.codelets:
return None
temp = formulas.Temperature
scale = ( 100.0 - temp + 10.0 ) / 15.0
# threshold = sum( [ c.urgency ** scale for c in self.codelets ] ) * utils.random()
urgsum = 0.0
for codelet in self.codelets:
urg = codelet.urgency ** scale
urgsum += urg
r = utils.random()
threshold = r * urgsum
chosen = None
urgencySum = 0.0
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: ")
for codelet in self.codelets:
urgencySum += codelet.urgency ** scale
if not chosen and urgencySum > threshold:
chosen = codelet
break
if not chosen:
chosen = self.codelets[0]
self.removeCodelet(chosen)
logging.info('chosen codelet\n\t%s, urgency = %s' % (chosen.name, chosen.urgency))
return chosen
def run(self, codelet):
methodName = re.sub('[ -]', '_', 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)
#global codeletsUsed
#codeletsUsed[methodName] = codeletsUsed.get(methodName,0) + 1
try:
if 'codelet' in args:
method(codelet)
else:
method()
except AssertionError:
pass
coderack = CodeRack()

133
coderackPressure.py Normal file
View File

@ -0,0 +1,133 @@
import logging
from formulas import Temperature
from slipnet import slipnet
class CoderackPressure(object):
def __init__(self, name):
self.name = name
def reset(self):
self.unmodifedValues = []
self.values = []
self.codelets = []
class CoderackPressures(object):
def __init__(self):
#logging.debug('coderackPressures.__init__()')
self.initialisePressures()
self.reset()
def initialisePressures(self):
#logging.debug('coderackPressures.initialisePressures()')
self.pressures = []
self.pressures += [CoderackPressure('Bottom Up Bonds')]
self.pressures += [CoderackPressure('Top Down Successor Bonds')]
self.pressures += [CoderackPressure('Top Down Predecessor Bonds')]
self.pressures += [CoderackPressure('Top Down Sameness Bonds')]
self.pressures += [CoderackPressure('Top Down Left Bonds')]
self.pressures += [CoderackPressure('Top Down Right Bonds')]
self.pressures += [CoderackPressure('Top Down Successor Group')]
self.pressures += [CoderackPressure('Top Down Predecessor Group')]
self.pressures += [CoderackPressure('Top Down Sameness Group')]
self.pressures += [CoderackPressure('Top Down Left Group')]
self.pressures += [CoderackPressure('Top Down Right Group')]
self.pressures += [CoderackPressure('Bottom Up Whole Group')]
self.pressures += [CoderackPressure('Replacement Finder')]
self.pressures += [CoderackPressure('Rule Codelets')]
self.pressures += [CoderackPressure('Rule Translator')]
self.pressures += [CoderackPressure('Bottom Up Correspondences')]
self.pressures += [CoderackPressure('Important Object Correspondences')]
self.pressures += [CoderackPressure('Breakers')]
def calculatePressures(self):
#logging.debug('coderackPressures.calculatePressures()')
scale = ( 100.0 - Temperature + 10.0 ) / 15.0
values = []
for pressure in self.pressures:
value = sum([c.urgency ** scale for c in pressure.codelets])
values += [value]
totalValue = sum(values)
if not totalValue:
totalValue = 1.0
values = [value / totalValue for value in values]
self.maxValue = max(values)
for pressure, value in zip(self.pressures, values):
pressure.values += [value * 100.0]
for codelet in self.removedCodelets:
if codelet.pressure:
codelet.pressure.codelets.removeElement(codelet)
self.removedCodelets = []
def reset(self):
#logging.debug('coderackPressures.reset()')
self.maxValue = 0.001
for pressure in self.pressures:
pressure.reset()
self.removedCodelets = []
def addCodelet(self, codelet):
node = None
i = -1
if codelet.name == 'bottom-up-bond-scout':
i = 0
if codelet.name == 'top-down-bond-scout--category':
node = codelet.arguments[0]
if node == slipnet.successor:
i = 1
elif node == slipnet.predecessor:
i = 2
else:
i = 3
if codelet.name == 'top-down-bond-scout--direction':
node = codelet.arguments[0]
if node == slipnet.left:
i = 4
elif node == slipnet.right:
i = 5
else:
i = 3
if codelet.name == 'top-down-group-scout--category':
node = codelet.arguments[0]
if node == slipnet.successorGroup:
i = 6
elif node == slipnet.predecessorGroup:
i = 7
else:
i = 8
if codelet.name == 'top-down-group-scout--direction':
node = codelet.arguments[0]
if node == slipnet.left:
i = 9
elif node == slipnet.right:
i = 10
if codelet.name == 'group-scout--whole-string':
i = 11
if codelet.name == 'replacement-finder':
i = 12
if codelet.name == 'rule-scout':
i = 13
if codelet.name == 'rule-translator':
i = 14
if codelet.name == 'bottom-up-correspondence-scout':
i = 15
if codelet.name == 'important-object-correspondence-scout':
i = 16
if codelet.name == 'breaker':
i = 17
if i >= 0:
self.pressures[i].codelets += [codelet]
if codelet.pressure:
codelet.pressure.codelets += [codelet] # XXX why do this
if i >= 0:
codelet.pressure = self.pressures[i] # when following with this ?
logging.info('Add %s: %d' % (codelet.name, i))
if node:
logging.info('Node: %s' % node.name)
def removeCodelet(self, codelet):
self.removedCodelets += [codelet]
def numberOfPressures(self):
return len(self.pressures)
coderackPressures = CoderackPressures()

156
conceptMapping.py Normal file
View File

@ -0,0 +1,156 @@
import logging
from slipnet import slipnet
class ConceptMapping(object):
def __init__(self, initialDescriptionType, targetDescriptionType, initialDescriptor, targetDescriptor, initialObject, targetObject):
logging.info('make a map: %s-%s' % (initialDescriptionType.get_name(), targetDescriptionType.get_name()))
self.initialDescriptionType = initialDescriptionType
self.targetDescriptionType = targetDescriptionType
self.initialDescriptor = initialDescriptor
self.targetDescriptor = targetDescriptor
self.initialObject = initialObject
self.targetObject = targetObject
self.label = initialDescriptor.getBondCategory(targetDescriptor)
def __repr__(self):
return '<ConceptMapping: %s from %s to %s>' % (self.__str__(), self.initialDescriptor, self.targetDescriptor)
def __str__(self):
if self.label:
return self.label.name
return 'anonymous'
def slipability(self):
association = self.__degreeOfAssociation()
if association == 100.0:
return 100.0
depth = self.__conceptualDepth() / 100.0
return association * ( 1 - depth * depth )
def __degreeOfAssociation(self):
#assumes the 2 descriptors are connected in the slipnet by at most 1 link
if self.initialDescriptor == self.targetDescriptor:
return 100.0
for link in self.initialDescriptor.lateralSlipLinks:
if link.destination == self.targetDescriptor:
return link.degreeOfAssociation()
return 0.0
def strength(self):
association = self.__degreeOfAssociation()
if association == 100.0:
return 100.0
depth = self.__conceptualDepth() / 100.0
return association * ( 1 + depth * depth )
def __conceptualDepth(self):
return (self.initialDescriptor.conceptualDepth + self.targetDescriptor.conceptualDepth ) / 2.0
def distinguishing(self):
if self.initialDescriptor == slipnet.whole and self.targetDescriptor == slipnet.whole:
return False
if not self.initialObject.distinguishingDescriptor(self.initialDescriptor):
return False
if not self.targetObject.distinguishingDescriptor(self.targetDescriptor):
return False
return True
def sameInitialType(self, other):
return self.initialDescriptionType == other.initialDescriptionType
def sameTargetType(self, other):
return self.targetDescriptionType == other.targetDescriptionType
def sameTypes(self, other):
return self.sameInitialType(other) and self.sameTargetType(other)
def sameInitialDescriptor(self, other):
return self.initialDescriptor == other.initialDescriptor
def sameTargetDescriptor(self, other):
return self.targetDescriptor == other.targetDescriptor
def sameDescriptors(self, other):
return self.sameInitialDescriptor(other) and self.sameTargetDescriptor(other)
def sameKind(self, other):
return self.sameTypes(other) and self.sameDescriptors(other)
def nearlySameKind(self, other):
return self.sameTypes(other) and self.sameInitialDescriptor(other)
def isContainedBy(self, mappings):
for mapping in mappings:
if self.sameKind(mapping):
return True
return False
def isNearlyContainedBy(self, mappings):
for mapping in mappings:
if self.nearlySameKind(mapping):
return True
return False
def related(self, other):
if self.initialDescriptor.related(other.initialDescriptor):
return True
return self.targetDescriptor.related(other.targetDescriptor)
def incompatible(self, other):
# Concept-mappings (a -> b) and (c -> d) are incompatible if a is
# related to c or if b is related to d, and the a -> b relationship is
# different from the c -> d relationship. E.g., rightmost -> leftmost
# is incompatible with right -> right, since rightmost is linked
# to right, but the relationships (opposite and identity) are different.
# Notice that slipnet distances are not looked at, only slipnet links. This
# should be changed eventually.
if not self.related(other):
return False
if not self.label or not other.label:
return False
if self.label != other.label:
return True
return False
def supports(self, other):
# Concept-mappings (a -> b) and (c -> d) support each other if a is related
# to c and if b is related to d and the a -> b relationship is the same as the
# c -> d relationship. E.g., rightmost -> rightmost supports right -> right
# and leftmost -> leftmost. Notice that slipnet distances are not looked
# at, only slipnet links. This should be changed eventually.
# If the two concept-mappings are the same, then return t. This
# means that letter->group supports letter->group, even though these
# concept-mappings have no label.
if self.initialDescriptor == other.initialDescriptor and self.targetDescriptor == other.targetDescriptor:
return True
# if the descriptors are not related return false
if not self.related(other):
return False
if not self.label or not other.label:
return False
if self.label == other.label:
return True
return False
def relevant(self):
return self.initialDescriptionType.fully_active() and self.targetDescriptionType.fully_active()
def slippage(self):
return self.label != slipnet.sameness and self.label != slipnet.identity
def symmetricVersion(self):
if not self.slippage():
return self
if self.targetDescriptor.getBondCategory(self.initialDescriptor) == self.label:
return self
return ConceptMapping(
self.targetDescriptionType,
self.initialDescriptionType,
self.targetDescriptor,
self.initialDescriptor1,
self.initialObject,
self.targetObject
)

68
copycat.py Normal file
View File

@ -0,0 +1,68 @@
import sys
import logging
logging.basicConfig(
level=logging.INFO,
#format='%(asctime)s %(filename)s:%(lineno)d %(message)s',
format='%(message)s',
filename='./copycat.log',
filemode='w'
)
from workspace import workspace
from workspaceFormulas import workspaceFormulas
from slipnet import slipnet
from temperature import temperature
from coderack import coderack
from coderackPressure import coderackPressures
def updateEverything():
workspace.updateEverything()
coderack.updateCodelets()
slipnet.update()
workspaceFormulas.updateTemperature()
coderackPressures.calculatePressures()
def mainLoop(lastUpdate):
temperature.tryUnclamp()
result = lastUpdate
if coderack.codeletsRun - lastUpdate >= slipnet.timeStepLength or not coderack.codeletsRun:
updateEverything()
result = coderack.codeletsRun
logging.debug('Number of codelets: %d' % len(coderack.codelets))
coderack.chooseAndRunCodelet()
return result
def runTrial():
"""Run a trial of the copycat algorithm"""
answers = {}
slipnet.reset()
workspace.reset()
coderack.reset()
lastUpdate = 0
while not workspace.foundAnswer:
lastUpdate = mainLoop(lastUpdate)
if workspace.rule:
answer = workspace.rule.finalAnswer
else:
answer = None
print '%d: %s' % (coderack.codeletsRun,answer)
answers[answer] = answers.get(answer,0) + 1
logging.debug('codelets used:')
for answer,count in answers.iteritems():
print '%s:%d' % (answer,count)
def main():
#slipnet.setConceptualDepths(50.0)
"""Run the program"""
argc = len(sys.argv)
if argc == 4:
workspace.setStrings(initial=sys.argv[1].lower(),modified=sys.argv[2].lower(),target=sys.argv[3].lower())
elif argc == 1:
workspace.setStrings(initial='abc',modified='abd',target='ijk')
else:
print >> sys.stderr, 'Usage: %s [initial modified target]' % sys.argv[0]
return
runTrial()
if __name__ == '__main__':
main()

189
correspondence.py Normal file
View File

@ -0,0 +1,189 @@
from workspace import workspace
from workspaceStructure import WorkspaceStructure
from formulas import getMappings
class Correspondence(WorkspaceStructure):
def __init__(self,objectFromInitial,objectFromTarget,conceptMappings,flipTargetObject):
WorkspaceStructure.__init__(self)
self.objectFromInitial = objectFromInitial
self.objectFromTarget = objectFromTarget
self.conceptMappings = conceptMappings
self.flipTargetObject = flipTargetObject
self.accessoryConceptMappings = []
def __repr__(self):
return '<%s>' % self.__str__()
def __str__(self):
return 'Correspondence between %s and %s' % (self.objectFromInitial,self.objectFromTarget)
def distinguishingConceptMappings(self):
return [ m for m in self.conceptMappings if m.distinguishing() ]
def relevantDistinguishingConceptMappings(self):
return [ m for m in self.conceptMappings if m.distinguishing() and m.relevant() ]
def extract_target_bond(self):
targetBond = False
if self.objectFromTarget.leftmost:
targetBond = self.objectFromTarget.rightBond
elif self.objectFromTarget.rightmost:
targetBond = self.objectFromTarget.leftBond
return targetBond
def extract_initial_bond(self):
initialBond = False
if self.objectFromInitial.leftmost:
initialBond = self.objectFromInitial.rightBond
elif self.objectFromInitial.rightmost:
initialBond = self.objectFromInitial.leftBond
return initialBond
def getIncompatibleBond(self):
initialBond = self.extract_initial_bond()
if not initialBond:
return None
targetBond = self.extract_target_bond()
if not targetBond:
return None
from conceptMapping import ConceptMapping
from slipnet import slipnet
if initialBond.directionCategory and targetBond.directionCategory:
mapping = ConceptMapping(
slipnet.directionCategory,
slipnet.directionCategory,
initialBond.directionCategory,
targetBond.directionCategory,
None,
None
)
for m in self.conceptMappings:
if m.incompatible(mapping):
return targetBond
return None
def getIncompatibleCorrespondences(self):
return [ o.correspondence for o in workspace.initial.objects if o and self.incompatible(o.correspondence) ]
def incompatible(self,other):
if not other:
return False
if self.objectFromInitial == other.objectFromInitial:
return True
if self.objectFromTarget == other.objectFromTarget:
return True
for mapping in self.conceptMappings:
for otherMapping in other.conceptMappings:
if mapping.incompatible(otherMapping):
return True
return False
def supporting(self,other):
if self == other:
return False
if self.objectFromInitial == other.objectFromInitial:
return False
if self.objectFromTarget == other.objectFromTarget:
return False
if self.incompatible(other):
return False
for mapping in self.distinguishingConceptMappings():
for otherMapping in other.distinguishingConceptMappings():
if mapping.supports(otherMapping):
return True
return False
def support(self):
from letter import Letter
if isinstance(self.objectFromInitial,Letter) and self.objectFromInitial.spansString():
return 100.0
if isinstance(self.objectFromTarget,Letter) and self.objectFromTarget.spansString():
return 100.0
total = sum([ c.totalStrength for c in workspace.correspondences() if self.supporting(c) ])
total = min(total,100.0)
return total
def updateInternalStrength(self):
"""A function of how many conceptMappings there are, their strength and how well they cohere"""
relevantDistinguishingMappings = self.relevantDistinguishingConceptMappings()
numberOfConceptMappings = len(relevantDistinguishingMappings)
if numberOfConceptMappings < 1:
self.internalStrength = 0.0
return
totalStrength = sum([ m.strength() for m in relevantDistinguishingMappings ])
averageStrength = totalStrength / numberOfConceptMappings
if numberOfConceptMappings == 1.0:
numberOfConceptMappingsFactor = 0.8
elif numberOfConceptMappings == 2.0:
numberOfConceptMappingsFactor = 1.2
else:
numberOfConceptMappingsFactor = 1.6
if self.internallyCoherent():
internalCoherenceFactor = 2.5
else:
internalCoherenceFactor = 1.0
internalStrength = averageStrength * internalCoherenceFactor * numberOfConceptMappingsFactor
self.internalStrength = min(internalStrength,100.0)
def updateExternalStrength(self):
self.externalStrength = self.support()
def internallyCoherent(self):
"""Whether any pair of relevant distinguishing mappings support each other"""
mappings = self.relevantDistinguishingConceptMappings()
for i in range(0,len(mappings)):
for j in range(0,len(mappings)):
if i != j:
if mappings[i].supports(mappings[j]):
return True
return False
def slippages(self):
mappings = [ m for m in self.conceptMappings if m.slippage() ]
mappings += [ m for m in self.accessoryConceptMappings if m.slippage() ]
return mappings
def reflexive(self):
if not self.objectFromInitial.correspondence:
return False
if self.objectFromInitial.correspondence.objectFromTarget == self.objectFromTarget:
return True
return False
def buildCorrespondence(self):
workspace.structures += [ self ]
if self.objectFromInitial.correspondence:
self.objectFromInitial.correspondence.breakCorrespondence()
if self.objectFromTarget.correspondence:
self.objectFromTarget.correspondence.breakCorrespondence()
self.objectFromInitial.correspondence = self
self.objectFromTarget.correspondence = self
# add mappings to accessory-concept-mapping-list
relevantMappings = self.relevantDistinguishingConceptMappings()
for mapping in relevantMappings:
if mapping.slippage():
self.accessoryConceptMappings += [ mapping.symmetricVersion() ]
from group import Group
if isinstance(self.objectFromInitial,Group) and isinstance(self.objectFromTarget,Group):
bondMappings = getMappings(
self.objectFromInitial,
self.objectFromTarget,
self.objectFromInitial.bondDescriptions,
self.objectFromTarget.bondDescriptions
)
for mapping in bondMappings:
self.accessoryConceptMappings += [ mapping ]
if mapping.slippage():
self.accessoryConceptMappings += [ mapping.symmetricVersion() ]
for mapping in self.conceptMappings:
if mapping.label:
mapping.label.activation = 100.0
def break_the_structure(self):
self.breakCorrespondence()
def breakCorrespondence(self):
workspace.structures.remove(self)
self.objectFromInitial.correspondence = None
self.objectFromTarget.correspondence = None

56
description.py Normal file
View File

@ -0,0 +1,56 @@
import logging
from workspaceStructure import WorkspaceStructure
class Description(WorkspaceStructure):
def __init__(self,workspaceObject,descriptionType,descriptor):
WorkspaceStructure.__init__(self)
self.object = workspaceObject
self.string = workspaceObject.string
self.descriptionType = descriptionType
self.descriptor = descriptor
def __repr__(self):
return '<Description: %s>' % self.__str__()
def __str__(self):
s = 'description(%s) of %s' % (self.descriptor.get_name(),self.object)
from workspace import workspace
if self.object.string == workspace.initial:
s += ' in initial string'
else:
s += ' in target string'
return s
def updateInternalStrength(self):
self.internalStrength = self.descriptor.conceptualDepth
def updateExternalStrength(self):
self.externalStrength = (self.localSupport() + self.descriptionType.activation) / 2
def localSupport(self):
from workspace import workspace
supporters = 0 # number of objects in the string with a descriptionType like self
for other in workspace.otherObjects(self.object):
if not ( self.object.isWithin(other) or other.isWithin(self.object) ):
for description in other.descriptions:
if description.descriptionType == self.descriptionType:
supporters += 1
results = { 0:0.0, 1:20.0, 2:60.0, 3:90.0 }
if supporters in results:
return results[supporters]
return 100.0
def build(self):
self.descriptionType.buffer = 100.0
self.descriptor.buffer = 100.0
if not self.object.hasDescription(self.descriptor):
logging.info('Add %s to descriptions' % self)
self.object.descriptions += [ self ]
def breakDescription(self):
from workspace import workspace
if self in workspace.structures:
workspace.structures.remove(self)
self.object.descriptions.remove(self)

146
formulas.py Normal file
View File

@ -0,0 +1,146 @@
import math #, random
import logging
import utils
from temperature import temperature
actualTemperature = Temperature = 100.0
def selectListPosition(probabilities):
total = sum(probabilities)
#logging.info('total: %s' % total)
r = utils.random()
stopPosition = total * r
#logging.info('stopPosition: %s' % stopPosition)
total = 0
index = 0
for probability in probabilities:
total += probability
if total > stopPosition:
return index
index += 1
return 0
def weightedAverage(values):
total = 0.0
totalWeights = 0.0
for value,weight in values:
total += value * weight
totalWeights += weight
if not totalWeights:
return 0.0
return total / totalWeights
def temperatureAdjustedValue(value):
#logging.info('Temperature: %s' % Temperature)
#logging.info('actualTemperature: %s' % actualTemperature)
return value ** (((100.0-Temperature)/30.0)+0.5)
def temperatureAdjustedProbability(value):
if not value or value == 0.5 or not temperature.value:
return value
if value < 0.5:
return 1.0 - temperatureAdjustedProbability(1.0 - value)
coldness = 100.0 - temperature.value
a = math.sqrt(coldness)
b = 10.0 - a
c = b / 100
d = c * ( 1.0 - ( 1.0 - value ) ) # aka c * value, but we're following the java
e = ( 1.0 - value ) + d
f = 1.0 - e
return max(f,0.5)
def coinFlip(chance=0.5):
return utils.random() < chance
def blur(value):
root = math.sqrt(value)
if coinFlip():
return value + root
return value - root
def chooseObjectFromList(objects,attribute):
if not objects:
return None
probabilities = []
for object in objects:
value = getattr(object,attribute)
probability = temperatureAdjustedValue(value)
logging.info('Object: %s, value: %d, probability: %d' % (object,value,probability))
probabilities += [ probability ]
index = selectListPosition(probabilities)
logging.info("Selected: %d" % index)
return objects[index]
def chooseRelevantDescriptionByActivation(workspaceObject):
descriptions = workspaceObject.relevantDescriptions()
if not descriptions:
return None
activations = [ description.descriptor.activation for description in descriptions ]
index = selectListPosition(activations)
return descriptions[ index ]
def similarPropertyLinks(slip_node):
result = []
for slip_link in slip_node.propertyLinks:
association = slip_link.degreeOfAssociation() / 100.0
probability = temperatureAdjustedProbability( association )
if coinFlip(probability):
result += [ slip_link ]
return result
def chooseSlipnodeByConceptualDepth(slip_nodes):
if not slip_nodes:
return None
depths = [ temperatureAdjustedValue(n.conceptualDepth) for n in slip_nodes ]
i = selectListPosition(depths)
return slip_nodes[ i ]
def __relevantCategory(objekt,slipnode):
return objekt.rightBond and objekt.rightBond.category == slipnode
def __relevantDirection(objekt,slipnode):
return objekt.rightBond and objekt.rightBond.directionCategory == slipnode
def __localRelevance(string,slipnode,relevance):
numberOfObjectsNotSpanning = numberOfMatches = 0.0
#logging.info("find relevance for a string: %s" % string);
for objekt in string.objects:
#logging.info('object: %s' % objekt)
if not objekt.spansString():
#logging.info('non spanner: %s' % objekt)
numberOfObjectsNotSpanning += 1.0
if relevance(objekt,slipnode):
numberOfMatches += 1.0
#logging.info("matches: %d, not spanning: %d" % (numberOfMatches,numberOfObjectsNotSpanning))
if numberOfObjectsNotSpanning == 1:
return 100.0 * numberOfMatches
return 100.0 * numberOfMatches / (numberOfObjectsNotSpanning - 1.0)
def localBondCategoryRelevance(string, category):
if len(string.objects) == 1:
return 0.0
return __localRelevance(string,category,__relevantCategory)
def localDirectionCategoryRelevance(string, direction):
return __localRelevance(string,direction,__relevantDirection)
def getMappings(objectFromInitial,objectFromTarget, initialDescriptions, targetDescriptions):
mappings = []
from conceptMapping import ConceptMapping
for initialDescription in initialDescriptions:
for targetDescription in targetDescriptions:
if initialDescription.descriptionType == targetDescription.descriptionType:
if initialDescription.descriptor == targetDescription.descriptor or initialDescription.descriptor.slipLinked(targetDescription.descriptor):
mapping = ConceptMapping(
initialDescription.descriptionType,
targetDescription.descriptionType,
initialDescription.descriptor,
targetDescription.descriptor,
objectFromInitial,
objectFromTarget
)
mappings += [ mapping ]
return mappings

237
group.py Normal file
View File

@ -0,0 +1,237 @@
import utils, logging
from workspace import workspace
from workspaceObject import WorkspaceObject
from slipnet import slipnet
import formulas
class Group(WorkspaceObject):
def __init__(self,string,groupCategory,directionCategory,facet,objectList,bondList):
WorkspaceObject.__init__(self,string)
self.groupCategory = groupCategory
self.directionCategory = directionCategory
self.facet = facet
self.objectList = objectList
self.bondList = bondList
self.bondCategory = self.groupCategory.getRelatedNode(slipnet.bondCategory)
leftObject = objectList[0]
rightObject = objectList[-1]
self.leftStringPosition = leftObject.leftStringPosition
self.leftmost = self.leftStringPosition == 1
self.rightStringPosition = rightObject.rightStringPosition
self.rightmost = self.rightStringPosition == len(self.string)
self.descriptions = []
self.bondDescriptions = []
self.extrinsicDescriptions = []
self.outgoingBonds = []
self.incomingBonds = []
self.bonds = []
self.leftBond = None
self.rightBond = None
self.correspondence = None
self.changed = False
self.newAnswerLetter = False
self.clampSalience = False
self.name = ''
from description import Description
if self.bondList and len(self.bondList):
firstFacet = self.bondList[0].facet
self.addBondDescription(Description(self, slipnet.bondFacet, firstFacet))
self.addBondDescription(Description(self, slipnet.bondCategory, self.bondCategory))
self.addDescription(slipnet.objectCategory, slipnet.group)
self.addDescription(slipnet.groupCategory, self.groupCategory)
if not self.directionCategory:
# sameness group - find letterCategory
letter = self.objectList[0].getDescriptor(self.facet)
self.addDescription(self.facet, letter)
if self.directionCategory:
self.addDescription(slipnet.directionCategory, self.directionCategory)
if self.spansString():
self.addDescription(slipnet.stringPositionCategory, slipnet.whole)
elif self.leftStringPosition == 1:
self.addDescription(slipnet.stringPositionCategory, slipnet.leftmost)
elif self.rightStringPosition == self.string.length:
self.addDescription(slipnet.stringPositionCategory, slipnet.rightmost)
elif self.middleObject():
self.addDescription(slipnet.stringPositionCategory, slipnet.middle)
#check whether or not to add length description category
probability = self.lengthDescriptionProbability()
if utils.random() < probability:
length = len(self.objectList)
if length < 6:
self.addDescription(slipnet.length, slipnet.numbers[length - 1])
def __str__(self):
s = self.string.__str__()
l = self.leftStringPosition - 1
r = self.rightStringPosition
return 'group[%d:%d] == %s' % ( l, r - 1, s[l: r ])
def getIncompatibleGroups(self):
result = []
for objekt in self.objectList:
while objekt.group:
result += [ objekt.group ]
objekt = objekt.group
return result
def addBondDescription(self,description):
self.bondDescriptions += [ description ]
def singleLetterGroupProbability(self):
numberOfSupporters = self.numberOfLocalSupportingGroups()
if not numberOfSupporters:
return 0.0
if numberOfSupporters == 1:
exp = 4.0
elif numberOfSupporters == 2:
exp = 2.0
else:
exp = 1.0
support = self.localSupport() / 100.0
activation = slipnet.length.activation / 100.0
supportedActivation = (support * activation) ** exp
return formulas.temperatureAdjustedProbability(supportedActivation)
def flippedVersion(self):
flippedBonds = [ b.flippedversion() for b in self.bondList ]
flippedGroup = self.groupCategory.getRelatedNode(slipnet.flipped)
flippedDirection = self.directionCategory.getRelatedNode(slipnet.flipped)
return Group(self.string, flippedGroup, flippedDirection, self.facet, self.objectList, flippedBonds)
def buildGroup(self):
workspace.objects += [ self ]
workspace.structures += [ self ]
self.string.objects += [ self ]
for objekt in self.objectList:
objekt.group = self
workspace.buildDescriptions(self)
self.activateDescriptions()
def activateDescriptions(self):
for description in self.descriptions:
logging.info('Activate: %s' % description)
description.descriptor.buffer = 100.0
def lengthDescriptionProbability(self):
length = len(self.objectList)
if length > 5:
return 0.0
cubedlength = length ** 3
fred = cubedlength * (100.0 - slipnet.length.activation) / 100.0
probability = 0.5 ** fred
value = formulas.temperatureAdjustedProbability(probability)
if value < 0.06:
value = 0.0 # otherwise 1/20 chance always
return value
def break_the_structure(self):
self.breakGroup()
def breakGroup(self):
while len(self.descriptions):
description = self.descriptions[-1]
description.breakDescription()
for objekt in self.objectList:
objekt.group = None
if self.group:
self.group.breakGroup()
if self in workspace.structures:
workspace.structures.remove(self)
if self in workspace.objects:
workspace.objects.remove(self)
if self in self.string.objects:
self.string.objects.remove(self)
if self.correspondence:
self.correspondence.breakCorrespondence()
if self.leftBond:
self.leftBond.breakBond()
if self.rightBond:
self.rightBond.breakBond()
def updateInternalStrength(self):
relatedBondAssociation = self.groupCategory.getRelatedNode(slipnet.bondCategory).degreeOfAssociation()
bondWeight = relatedBondAssociation ** 0.98
length = len(self.objectList)
if length == 1:
lengthFactor = 5.0
elif length == 2:
lengthFactor = 20.0
elif length == 3:
lengthFactor = 60.0
else:
lengthFactor = 90.0
lengthWeight = 100.0 - bondWeight
weightList = ( (relatedBondAssociation, bondWeight), (lengthFactor, lengthWeight) )
self.internalStrength = formulas.weightedAverage(weightList)
def updateExternalStrength(self):
if self.spansString():
self.externalStrength = 100.0
else:
self.externalStrength = self.localSupport()
def localSupport(self):
numberOfSupporters = self.numberOfLocalSupportingGroups()
if numberOfSupporters == 0.0:
return 0.0
supportFactor = min(1.0,0.6 ** (1 / (numberOfSupporters ** 3 )))
densityFactor = 100.0 * ((self.localDensity() / 100.0) ** 0.5)
return densityFactor * supportFactor
def numberOfLocalSupportingGroups(self):
count = 0
for objekt in self.string.objects:
if isinstance(objekt,Group):
if objekt.rightStringPosition < self.leftStringPosition or objekt.leftStringPosition > self.rightStringPosition:
if objekt.groupCategory == self.groupCategory and objekt.directionCategory == self.directionCategory:
count += 1
return count
def localDensity(self):
numberOfSupporters = self.numberOfLocalSupportingGroups()
halfLength = len(self.string) / 2.0
return 100.0 * numberOfSupporters / halfLength
def sameGroup(self,other):
if self.leftStringPosition != other.leftStringPosition:
return False
if self.rightStringPosition != other.rightStringPosition:
return False
if self.groupCategory != other.groupCategory:
return False
if self.directionCategory != other.directionCategory:
return False
if self.facet != other.facet:
return False
return True
def morePossibleDescriptions(self,node):
result = []
i = 1
for number in slipnet.numbers:
if node == number and len(self.objects) == i:
result += [ node ]
i += 1
return result
def distinguishingDescriptor(self,descriptor):
"""Whether no other object of the same type (group) has the same descriptor"""
if not WorkspaceObject.distinguishingDescriptor(self,descriptor):
return False
for objekt in self.string.objects:
# check to see if they are of the same type
if isinstance(objekt,Group) and objekt != self:
# check all descriptions for the descriptor
for description in objekt.descriptions:
if description.descriptor == descriptor:
return False
return True

14
grouprun.py Normal file
View File

@ -0,0 +1,14 @@
from workspace import workspace
class GroupRun(object):
def __init__(self):
self.name = 'xxx'
self.maximumNumberOfRuns = 1000
self.runStrings = []
self.answers = []
self.scores = [0] * 100
self.initial = workspace.initial
self.modified = workspace.modified
self.target = workspace.target
groupRun = GroupRun()

48
letter.py Normal file
View File

@ -0,0 +1,48 @@
from workspaceObject import WorkspaceObject
from slipnet import slipnet
class Letter(WorkspaceObject):
def __init__(self,string,position,length):
WorkspaceObject.__init__(self,string)
from workspace import workspace
workspace.objects += [ self ]
string.objects += [self ]
self.leftStringPosition = position
self.leftmost = self.leftStringPosition == 1
self.rightStringPosition = position
self.rightmost = self.rightStringPosition == length
def describe(self,position,length):
if length == 1:
self.addDescription(slipnet.stringPositionCategory,slipnet.single)
if self.leftmost and length > 1: # ? why check length ?
self.addDescription(slipnet.stringPositionCategory,slipnet.leftmost)
if self.rightmost and length > 1: # ? why check length ?
self.addDescription(slipnet.stringPositionCategory,slipnet.rightmost)
if length > 2 and position * 2 == length + 1:
self.addDescription(slipnet.stringPositionCategory,slipnet.middle)
def __repr__(self):
return '<Letter: %s>' % self.__str__()
def __str__(self):
if not self.string:
return ''
i = self.leftStringPosition - 1
if len(self.string) <= i:
raise ValueError, 'len(self.string) <= self.leftStringPosition :: %d <= %d' % (len(self.string),self.leftStringPosition)
return self.string[ i ]
def distinguishingDescriptor(self,descriptor):
"""Whether no other object of the same type (letter) has the same descriptor"""
if not WorkspaceObject.distinguishingDescriptor(self,descriptor):
return False
for objekt in self.string.objects:
# check to see if they are of the same type
if isinstance(objekt,Letter) and objekt != self:
# check all descriptions for the descriptor
for description in objekt.descriptions:
if description.descriptor == descriptor:
return False
return True

9
replacement.py Normal file
View File

@ -0,0 +1,9 @@
from workspaceStructure import WorkspaceStructure
class Replacement(WorkspaceStructure):
def __init__(self, objectFromInitial, objectFromModified, relation):
WorkspaceStructure.__init__(self)
self.objectFromInitial = objectFromInitial
self.objectFromModified = objectFromModified
self.relation = relation

134
rule.py Normal file
View File

@ -0,0 +1,134 @@
from slipnet import slipnet
from workspace import workspace
from workspaceStructure import WorkspaceStructure
from formulas import *
class Rule(WorkspaceStructure):
def __init__(self,facet,descriptor,category,relation):
WorkspaceStructure.__init__(self)
self.facet = facet
self.descriptor = descriptor
self.category = category
self.relation = relation
def __str__(self):
if not self.facet:
return 'Empty rule'
return 'replace %s of %s %s by %s' % (self.facet.name, self.descriptor.name, self.category.name, self.relation.name)
def updateExternalStrength(self):
self.externalStrength = self.internalStrength
def updateInternalStrength(self):
if not ( self.descriptor and self.relation ):
self.internalStrength = 0.0
return
averageDepth = ( self.descriptor.conceptualDepth + self.relation.conceptualDepth ) / 2.0
averageDepth **= 1.1
# see if the object corresponds to an object
# if so, see if the descriptor is present (modulo slippages) in the
# corresponding object
changedObjects = [ o for o in workspace.initial.objects if o.changed ]
changed = changedObjects[0]
sharedDescriptorTerm = 0.0
if changed and changed.correspondence:
targetObject = changed.correspondence.objectFromTarget
slippages = workspace.slippages()
slipnode = self.descriptor.applySlippages(slippages)
if not targetObject.hasDescription(slipnode):
self.internalStrength = 0.0
return
sharedDescriptorTerm = 100.0
sharedDescriptorWeight = ((100.0 - self.descriptor.conceptualDepth) / 10.0) ** 1.4
depthDifference = 100.0 - abs(self.descriptor.conceptualDepth - self.relation.conceptualDepth)
weights = ( (depthDifference,12), (averageDepth,18), (sharedDescriptorTerm,sharedDescriptorWeight) )
self.internalStrength = weightedAverage( weights )
if self.internalStrength > 100.0:
self.internalStrength = 100.0
def ruleEqual(self,other):
if not other:
return False
if self.relation != other.relation:
return False
if self.facet != other.facet:
return False
if self.category != other.category:
return False
if self.descriptor != other.descriptor:
return False
return True
def activateRuleDescriptions(self):
if self.relation:
self.relation.buffer = 100.0
if self.facet:
self.facet.buffer = 100.0
if self.category:
self.category.buffer = 100.0
if self.descriptor:
self.descriptor.buffer = 100.0
def incompatibleRuleCorrespondence(self, correspondence):
if not correspondence:
return False
# find changed object
changeds = [ o for o in workspace.initial.objects if o.changed ]
if not changeds:
return False
changed = changeds[0]
if correspondence.objectFromInitial != changed:
return False
# it is incompatible if the rule descriptor is not in the mapping list
if len([ m for m in correspondence.conceptMappings if m.initialDescriptor == self.descriptor ]):
return False
return True
def __changeString(self,string):
# applies the changes to self string ie. successor
if self.facet == slipnet.length:
if self.relation == slipnet.predecessor:
return string[0:-1]
if self.relation == slipnet.successor:
return string + string[0:1]
return string
# apply character changes
if self.relation == slipnet.predecessor:
if 'a' in string:
return None
return ''.join([ chr(ord(c) - 1) for c in string])
elif self.relation == slipnet.successor:
if 'z' in string:
return None
return ''.join([ chr(ord(c) + 1) for c in string])
else:
return self.relation.name.lower()
def buildTranslatedRule(self):
slippages = workspace.slippages()
self.category = self.category.applySlippages(slippages)
self.facet = self.facet.applySlippages(slippages)
self.descriptor = self.descriptor.applySlippages(slippages)
self.relation = self.relation.applySlippages(slippages)
# generate the final string
self.finalAnswer = workspace.targetString
changeds = [ o for o in workspace.target.objects if
o.hasDescription(self.descriptor) and
o.hasDescription(self.category) ]
changed = changeds and changeds[0] or None
logging.debug('changed object = %s' % changed)
if changed:
left = changed.leftStringPosition
startString = ''
if left > 1:
startString = self.finalAnswer[0: left - 1]
right = changed.rightStringPosition
middleString = self.__changeString(self.finalAnswer[left - 1: right])
if not middleString:
return False
endString = ''
if right < len(self.finalAnswer):
endString = self.finalAnswer[right:]
self.finalAnswer = startString + middleString + endString
return True

28
sliplink.py Normal file
View File

@ -0,0 +1,28 @@
#from slipnode import Slipnode
class Sliplink(object):
def __init__(self, source, destination, label=None, length=0.0):
self.source = source
self.destination = destination
self.label = label
self.fixedLength = length
source.outgoingLinks += [self]
destination.incomingLinks += [self]
def degreeOfAssociation(self):
if self.fixedLength > 0 or not self.label:
return 100.0 - self.fixedLength
return self.label.degreeOfAssociation()
def intrinsicDegreeOfAssociation(self):
if self.fixedLength > 1:
return 100.0 - self.fixedLength
if self.label:
return 100.0 - self.label.intrinsicLinkLength
return 0.0
def spread_activation(self):
self.destination.buffer += self.intrinsicDegreeOfAssociation()
def points_at(self, other):
return self.destination == other

252
slipnet.py Normal file
View File

@ -0,0 +1,252 @@
import logging
from slipnode import Slipnode
from sliplink import Sliplink
class SlipNet(object):
def __init__(self):
logging.debug("SlipNet.__init__()")
self.initiallyClampedSlipnodes = []
self.slipnodes = []
self.sliplinks = []
self.bondFacets = []
self.timeStepLength = 15
self.numberOfUpdates = 0
self.__addInitialNodes()
self.__addInitialLinks()
self.predecessor = None
def __repr__(self):
return '<slipnet>'
def setConceptualDepths(self, depth):
logging.debug('slipnet set all depths to %f' % depth)
[node.setConceptualDepth(depth) for node in self.slipnodes]
def reset(self):
logging.debug('slipnet.reset()')
self.numberOfUpdates = 0
for node in self.slipnodes:
node.reset()
if node in self.initiallyClampedSlipnodes:
node.clampHigh()
def update(self):
logging.debug('slipnet.update()')
self.numberOfUpdates += 1
if self.numberOfUpdates == 50:
[node.unclamp() for node in self.initiallyClampedSlipnodes]
[node.update() for node in self.slipnodes]
# Note - spreadActivation() affects more than one node, so the following
# cannot go in a general "for node" loop with the other node actions
for node in self.slipnodes:
node.spread_activation()
for node in self.slipnodes:
node.addBuffer()
node.jump()
node.buffer = 0.0
def __addInitialNodes(self):
self.slipnodes = []
self.letters = []
for c in 'abcdefghijklmnopqrstuvwxyz':
slipnode = self.__addNode(c, 10.0)
self.letters += [slipnode]
self.numbers = []
for c in '12345':
slipnode = self.__addNode(c, 30.0)
self.numbers += [slipnode]
# string positions
self.leftmost = self.__addNode('leftmost', 40.0)
self.rightmost = self.__addNode('rightmost', 40.0)
self.middle = self.__addNode('middle', 40.0)
self.single = self.__addNode('single', 40.0)
self.whole = self.__addNode('whole', 40.0)
# alphabetic positions
self.first = self.__addNode('first', 60.0)
self.last = self.__addNode('last', 60.0)
# directions
self.left = self.__addNode('left', 40.0)
self.left.codelets += ['top-down-bond-scout--direction']
self.left.codelets += ['top-down-group-scout--direction']
self.right = self.__addNode('right', 40.0)
self.right.codelets += ['top-down-bond-scout--direction']
self.right.codelets += ['top-down-group-scout--direction']
# bond types
self.predecessor = self.__addNode('predecessor', 50.0, 60.0)
self.predecessor.codelets += ['top-down-bond-scout--category']
self.successor = self.__addNode('successor', 50.0, 60.0)
self.successor.codelets += ['top-down-bond-scout--category']
self.sameness = self.__addNode('sameness', 80.0)
self.sameness.codelets += ['top-down-bond-scout--category']
# group types
self.predecessorGroup = self.__addNode('predecessorGroup', 50.0)
self.predecessorGroup.codelets += ['top-down-group-scout--category']
self.successorGroup = self.__addNode('successorGroup', 50.0)
self.successorGroup.codelets += ['top-down-group-scout--category']
self.samenessGroup = self.__addNode('samenessGroup', 80.0)
self.samenessGroup.codelets += ['top-down-group-scout--category']
# other relations
self.identity = self.__addNode('identity', 90.0)
self.opposite = self.__addNode('opposite', 90.0, 80.0)
# objects
self.letter = self.__addNode('letter', 20.0)
self.group = self.__addNode('group', 80.0)
# categories
self.letterCategory = self.__addNode('letterCategory', 30.0)
self.stringPositionCategory = self.__addNode('stringPositionCategory', 70.0)
self.stringPositionCategory.codelets += ['top-down-description-scout']
self.alphabeticPositionCategory = self.__addNode('alphabeticPositionCategory', 80.0)
self.alphabeticPositionCategory.codelets += ['top-down-description-scout']
self.directionCategory = self.__addNode('directionCategory', 70.0)
self.bondCategory = self.__addNode('bondCategory', 80.0)
self.groupCategory = self.__addNode('groupCategory', 80.0)
self.length = self.__addNode('length', 60.0)
self.objectCategory = self.__addNode('objectCategory', 90.0)
self.bondFacet = self.__addNode('bondFacet', 90.0)
# specify the descriptor types that bonds can form between
self.bondFacets += [self.letterCategory]
self.bondFacets += [self.length]
#
self.initiallyClampedSlipnodes += [self.letterCategory]
self.letterCategory.clamped = True
self.initiallyClampedSlipnodes += [self.stringPositionCategory]
self.stringPositionCategory.clamped = True
def __addInitialLinks(self):
self.sliplinks = []
self.__link_items_to_their_neighbours(self.letters)
self.__link_items_to_their_neighbours(self.numbers)
# letter categories
for letter in self.letters:
self.__addInstanceLink(self.letterCategory, letter, 97.0)
self.__addCategoryLink(self.samenessGroup, self.letterCategory, 50.0)
# lengths
for number in self.numbers:
self.__addInstanceLink(self.length, number, 100.0)
self.__addNonSlipLink(self.predecessorGroup, self.length, length=95.0)
self.__addNonSlipLink(self.successorGroup, self.length, length=95.0)
self.__addNonSlipLink(self.samenessGroup, self.length, length=95.0)
# opposites
self.__addOppositeLink(self.first, self.last)
self.__addOppositeLink(self.leftmost, self.rightmost)
self.__addOppositeLink(self.left, self.right)
self.__addOppositeLink(self.successor, self.predecessor)
self.__addOppositeLink(self.successorGroup, self.predecessorGroup)
# properties
self.__addPropertyLink(self.letters[0], self.first, 75.0)
self.__addPropertyLink(self.letters[-1], self.last, 75.0)
# object categories
self.__addInstanceLink(self.objectCategory, self.letter, 100.0)
self.__addInstanceLink(self.objectCategory, self.group, 100.0)
# string positions
self.__addInstanceLink(self.stringPositionCategory, self.leftmost, 100.0)
self.__addInstanceLink(self.stringPositionCategory, self.rightmost, 100.0)
self.__addInstanceLink(self.stringPositionCategory, self.middle, 100.0)
self.__addInstanceLink(self.stringPositionCategory, self.single, 100.0)
self.__addInstanceLink(self.stringPositionCategory, self.whole, 100.0)
# alphabetic positions
self.__addInstanceLink(self.alphabeticPositionCategory, self.first, 100.0)
self.__addInstanceLink(self.alphabeticPositionCategory, self.last, 100.0)
# direction categories
self.__addInstanceLink(self.directionCategory, self.left, 100.0)
self.__addInstanceLink(self.directionCategory, self.right, 100.0)
# bond categories
self.__addInstanceLink(self.bondCategory, self.predecessor, 100.0)
self.__addInstanceLink(self.bondCategory, self.successor, 100.0)
self.__addInstanceLink(self.bondCategory, self.sameness, 100.0)
# group categories
self.__addInstanceLink(self.groupCategory, self.predecessorGroup, 100.0)
self.__addInstanceLink(self.groupCategory, self.successorGroup, 100.0)
self.__addInstanceLink(self.groupCategory, self.samenessGroup, 100.0)
# link bonds to their groups
self.__addNonSlipLink(self.sameness, self.samenessGroup, label=self.groupCategory, length=30.0)
self.__addNonSlipLink(self.successor, self.successorGroup, label=self.groupCategory, length=60.0)
self.__addNonSlipLink(self.predecessor, self.predecessorGroup, label=self.groupCategory, length=60.0)
# link bond groups to their bonds
self.__addNonSlipLink(self.samenessGroup, self.sameness, label=self.bondCategory, length=90.0)
self.__addNonSlipLink(self.successorGroup, self.successor, label=self.bondCategory, length=90.0)
self.__addNonSlipLink(self.predecessorGroup, self.predecessor, label=self.bondCategory, length=90.0)
# bond facets
self.__addInstanceLink(self.bondFacet, self.letterCategory, 100.0)
self.__addInstanceLink(self.bondFacet, self.length, 100.0)
# letter category to length
self.__addSlipLink(self.letterCategory, self.length, length=95.0)
self.__addSlipLink(self.length, self.letterCategory, length=95.0)
# letter to group
self.__addSlipLink(self.letter, self.group, length=90.0)
self.__addSlipLink(self.group, self.letter, length=90.0)
# direction-position, direction-neighbour, position-neighbour
self.__addBidirectionalLink(self.left, self.leftmost, 90.0)
self.__addBidirectionalLink(self.right, self.rightmost, 90.0)
self.__addBidirectionalLink(self.right, self.leftmost, 100.0)
self.__addBidirectionalLink(self.left, self.rightmost, 100.0)
self.__addBidirectionalLink(self.leftmost, self.first, 100.0)
self.__addBidirectionalLink(self.rightmost, self.first, 100.0)
self.__addBidirectionalLink(self.leftmost, self.last, 100.0)
self.__addBidirectionalLink(self.rightmost, self.last, 100.0)
# other
self.__addSlipLink(self.single, self.whole, length=90.0)
self.__addSlipLink(self.whole, self.single, length=90.0)
def __addLink(self, source, destination, label=None, length=0.0):
link = Sliplink(source, destination, label=label, length=length)
self.sliplinks += [link]
return link
def __addSlipLink(self, source, destination, label=None, length=0.0):
link = self.__addLink(source, destination, label, length)
source.lateralSlipLinks += [link]
def __addNonSlipLink(self, source, destination, label=None, length=0.0):
link = self.__addLink(source, destination, label, length)
source.lateralNonSlipLinks += [link]
def __addBidirectionalLink(self, source, destination, length):
self.__addNonSlipLink(source, destination, length=length)
self.__addNonSlipLink(destination, source, length=length)
def __addCategoryLink(self, source, destination, length):
#noinspection PyArgumentEqualDefault
link = self.__addLink(source, destination, None, length)
source.categoryLinks += [link]
def __addInstanceLink(self, source, destination, length):
categoryLength = source.conceptualDepth - destination.conceptualDepth
self.__addCategoryLink(destination, source, categoryLength)
#noinspection PyArgumentEqualDefault
link = self.__addLink(source, destination, None, length)
source.instanceLinks += [link]
def __addPropertyLink(self, source, destination, length):
#noinspection PyArgumentEqualDefault
link = self.__addLink(source, destination, None, length)
source.propertyLinks += [link]
def __addOppositeLink(self, source, destination):
self.__addSlipLink(source, destination, label=self.opposite)
self.__addSlipLink(destination, source, label=self.opposite)
def __addNode(self, name, depth, length=0):
slipnode = Slipnode(name, depth, length)
self.slipnodes += [slipnode]
return slipnode
def __link_items_to_their_neighbours(self,items):
previous = items[0]
for item in items[1:]:
self.__addNonSlipLink(previous, item, label=self.successor)
self.__addNonSlipLink(item, previous, label=self.predecessor)
previous = item
slipnet = SlipNet()

161
slipnode.py Normal file
View File

@ -0,0 +1,161 @@
import math
import utils
import logging
def full_activation():
return 100
def jump_threshold():
return 55.0
class Slipnode(object):
def __init__(self, name, depth, length=0.0):
# logging.info('depth to %s for %s' % (depth,name))
self.conceptual_depth = depth
self.usualConceptualDepth = depth
self.name = name
self.intrinsicLinkLength = length
self.shrunkLinkLength = length * 0.4
self.activation = 0.0
self.buffer = 0.0
self.clamped = False
self.bondFacetFactor = 0.0
self.categoryLinks = []
self.instanceLinks = []
self.propertyLinks = []
self.lateralSlipLinks = []
self.lateralNonSlipLinks = []
self.incomingLinks = []
self.outgoingLinks = []
self.codelets = []
self.clampBondDegreeOfAssociation = False
def __repr__(self):
return '<Slipnode: %s>' % self.name
def reset(self):
self.buffer = 0.0
self.activation = 0.0
def clampHigh(self):
self.clamped = True
self.activation = 100.0
def unclamp(self):
self.clamped = False
def setConceptualDepth(self, depth):
logging.info('set depth to %s for %s' % (depth, self.name))
self.conceptual_depth = depth
def category(self):
if not len(self.categoryLinks):
return None
link = self.categoryLinks[0]
return link.destination
def fully_active(self):
"""Whether this node has full activation"""
return self.activation > full_activation() - 0.00001 # allow a little leeway for floats
def activate_fully(self):
"""Make this node fully active"""
self.activation = full_activation()
def bondDegreeOfAssociation(self):
linkLength = self.intrinsicLinkLength
if (not self.clampBondDegreeOfAssociation) and self.fully_active():
linkLength = self.shrunkLinkLength
result = math.sqrt(100 - linkLength) * 11.0
return min(100.0, result)
def degreeOfAssociation(self):
linkLength = self.intrinsicLinkLength
if self.fully_active():
linkLength = self.shrunkLinkLength
return 100.0 - linkLength
def update(self):
act = self.activation
self.oldActivation = act
self.buffer -= self.activation * ( 100.0 - self.conceptual_depth) / 100.0
def linked(self, other):
"""Whether the other is among the outgoing links"""
return self.points_at(self.outgoingLinks, other)
def slipLinked(self, other):
"""Whether the other is among the lateral links"""
return self.points_at(self.lateralSlipLinks, other)
def points_at(self, links, other):
"""Whether any of the links points at the other"""
return any([l.points_at(other) for l in links])
def related(self, other):
"""Same or linked"""
return self == other or self.linked(other)
def applySlippages(self, slippages):
for slippage in slippages:
if self == slippage.initialDescriptor:
return slippage.targetDescriptor
return self
def getRelatedNode(self, relation):
"""Return the node that is linked to this node via this relation.
If no linked node is found, return None
"""
from slipnet import slipnet
if relation == slipnet.identity:
return self
destinations = [l.destination for l in self.outgoingLinks if l.label == relation]
if destinations:
return destinations[0]
node = None
return node
def getBondCategory(self, destination):
"""Return the label of the link between these nodes if it exists.
If it does not exist return None
"""
from slipnet import slipnet
result = None
if self == destination:
result = slipnet.identity
else:
for link in self.outgoingLinks:
if link.destination == destination:
result = link.label
break
if result:
logging.info('Got bond: %s' % result.name)
else:
logging.info('Got no bond')
return result
def spread_activation(self):
if self.fully_active():
[ link.spread_activation() for link in self.outgoingLinks ]
def addBuffer(self):
if not self.clamped:
self.activation += self.buffer
self.activation = min(self.activation, 100)
self.activation = max(self.activation, 0)
def jump(self):
value = (self.activation / 100.0) ** 3
#logging.info('jumping for %s at activation %s' % (self.name,self.activation))
if self.activation > jump_threshold() and utils.random() < value and not self.clamped:
self.activate_fully()
def get_name(self):
if len(self.name) == 1:
return self.name.upper()
return self.name

23
temperature.py Normal file
View File

@ -0,0 +1,23 @@
import logging
class Temperature(object):
def __init__(self):
self.value = 100.0
self.clamped = True
self.clampTime = 30
def update(self, value):
logging.debug('update to %s' % value)
self.value = value
def tryUnclamp(self):
from coderack import coderack
if self.clamped and coderack.codeletsRun >= self.clampTime:
logging.info('unclamp temperature at %d' % coderack.codeletsRun)
self.clamped = False
def log(self):
logging.debug('temperature.value: %f' % self.value)
temperature = Temperature()

2
unready.py Normal file
View File

@ -0,0 +1,2 @@
from exceptions import NotImplementedError
raise NotImplementedError

140
utils.py Normal file
View File

@ -0,0 +1,140 @@
def any(things):
"""Return True if any of the things are True.
things should be iterable.
If the things are empty, then we can't say any are True
>>> any([])
False
If all the things are False, then we can't say any are True
>>> any([False,False,False])
False
If all the things are equivalent to False, then we can't say any are True
>>> any([0,[],''])
False
The type of the true thing should not matter
>>> any([1,[],''])
True
>>> any([0,(2,),''])
True
>>> any([0,[],'foo'])
True
>>> any([0,[],True,''])
True
It should not matter where the True thing is
>>> any((True,False,False,False,False,))
True
>>> any((False,False,True,False,False,))
True
>>> any((False,False,False,False,True,))
True
The size of the sequence should not matter
>>> True == any((True,)) == any((True,True,)) == any((True,True,True,True,))
True
Any string is True
>>> any('foo')
True
Except an empty string
>>> any('')
False
The function cannot be applied to ints
>>> any(7)
Traceback (most recent call last):
...
TypeError: iteration over non-sequence
"""
for thing in things:
if thing:
return True
return False
def all(things):
"""Return True if all of the things are True.
things should be iterable.
If the things are empty, then we can't say all are True
>>> all([])
False
If all the things are False, then we can't say all are True
>>> all([False,False,False])
False
If all the things are equivalent to False, then we can't say all are True
>>> all([0,[],''])
False
The type of the false thing should not matter
>>> all([0,True,True,])
False
>>> all([True,(),True,])
False
>>> all([True,True,'',])
False
Position of the false thing should not matter
>>> all((False,True,True,))
False
>>> all((True,False,True,))
False
>>> all((True,True,False,))
False
any string is True
>>> all('foo')
True
Except an empty string
>>> all('')
False
The function cannot be applied to ints
>>> all(7)
Traceback (most recent call last):
...
TypeError: iteration over non-sequence
"""
for thing in things:
if not thing:
return False
return len(things) > 0
import logging
seed = 999.0
count = 0
testably_random = True
def random():
global testably_random
if testably_random:
from random import random
return random()
global seed
global count
seed += 1.0
count += 1
if seed > 1999:
seed = 0.0
logging.info("count: %d" % count)
#if seed == 998:
# sys.exit(1)
return seed / 2000.0
def choice(aList):
i = int(random() * len(aList))
return aList[i]
if __name__ == '__main__':
import doctest
doctest.testmod()

158
workspace.py Normal file
View File

@ -0,0 +1,158 @@
import logging
from workspaceString import WorkspaceString
unknownAnswer = '?'
class Workspace(object):
def __init__(self):
#logging.debug('workspace.__init__()')
self.setStrings('', '', '')
self.reset()
self.totalUnhappiness = 0.0
self.intraStringUnhappiness = 0.0
self.interStringUnhappiness = 0.0
def __repr__(self):
return '<Workspace trying %s:%s::%s:?>' % (self.initialString, self.modifiedString, self.targetString)
def setStrings(self, initial, modified, target):
self.targetString = target
self.initialString = initial
self.modifiedString = modified
def reset(self):
#logging.debug('workspace.reset()')
self.foundAnswer = False
self.changedObject = None
self.objects = []
self.structures = []
self.rule = None
self.initial = WorkspaceString(self.initialString)
self.modified = WorkspaceString(self.modifiedString)
self.target = WorkspaceString(self.targetString)
def __adjustUnhappiness(self, values):
result = sum(values) / 2
if result > 100.0:
result = 100.0
return result
def assessUnhappiness(self):
self.intraStringUnhappiness = self.__adjustUnhappiness([o.relativeImportance * o.intraStringUnhappiness for o in self.objects])
self.interStringUnhappiness = self.__adjustUnhappiness([o.relativeImportance * o.interStringUnhappiness for o in self.objects])
self.totalUnhappiness = self.__adjustUnhappiness([o.relativeImportance * o.totalUnhappiness for o in self.objects])
def assessTemperature(self):
self.calculateIntraStringUnhappiness()
self.calculateInterStringUnhappiness()
self.calculateTotalUnhappiness()
def calculateIntraStringUnhappiness(self):
values = [o.relativeImportance * o.intraStringUnhappiness for o in self.objects]
value = sum(values) / 2.0
self.intraStringUnhappiness = min(value, 100.0)
def calculateInterStringUnhappiness(self):
values = [o.relativeImportance * o.interStringUnhappiness for o in self.objects]
value = sum(values) / 2.0
self.interStringUnhappiness = min(value, 100.0)
def calculateTotalUnhappiness(self):
for o in self.objects:
logging.info("object: %s, totalUnhappiness: %d, relativeImportance: %d" % (
o, o.totalUnhappiness, o.relativeImportance * 1000))
values = [o.relativeImportance * o.totalUnhappiness for o in self.objects]
value = sum(values) / 2.0
self.totalUnhappiness = min(value, 100.0)
def updateEverything(self):
for structure in self.structures:
structure.updateStrength()
for obj in self.objects:
obj.updateValue()
self.initial.updateRelativeImportance()
self.target.updateRelativeImportance()
self.initial.updateIntraStringUnhappiness()
self.target.updateIntraStringUnhappiness()
def otherObjects(self, anObject):
return [o for o in self.objects if o != anObject]
def numberOfUnrelatedObjects(self):
"""A list of all objects in the workspace that have at least one bond slot open."""
objects = [o for o in self.objects if o.string == self.initial or o.string == self.target]
#print 'A: %d' % len(objects)
objects = [o for o in objects if not o.spansString()]
#print 'B: %d' % len(objects)
objects = [o for o in objects if (not o.leftBond and not o.leftmost) or (not o.rightBond and not o.rightmost)]
#print 'C: %d' % len(objects)
#objects = [ o for o in objects if ]
#print 'D: %d' % len(objects)
return len(objects)
def numberOfUngroupedObjects(self):
"""A list of all objects in the workspace that have no group."""
objects = [o for o in self.objects if o.string == self.initial or o.string == self.target]
objects = [o for o in objects if not o.spansString()]
objects = [o for o in objects if not o.group]
return len(objects)
def numberOfUnreplacedObjects(self):
"""A list of all objects in the inital string that have not been replaced."""
from letter import Letter
objects = [o for o in self.objects if o.string == self.initial and isinstance(o, Letter)]
objects = [o for o in objects if not o.replacement]
return len(objects)
def numberOfUncorrespondingObjects(self):
"""A list of all objects in the inital string that have not been replaced."""
objects = [o for o in self.objects if o.string == self.initial or o.string == self.target]
objects = [o for o in objects if not o.correspondence]
return len(objects)
def numberOfBonds(self):
"""The number of bonds in the workspace"""
from bond import Bond
return len([o for o in self.structures if isinstance(o, Bond)])
def correspondences(self):
from correspondence import Correspondence
return [s for s in self.structures if isinstance(s, Correspondence)]
def slippages(self):
result = []
if self.changedObject and self.changedObject.correspondence:
result = [m for m in self.changedObject.correspondence.conceptMappings]
for objekt in workspace.initial.objects:
if objekt.correspondence:
for mapping in objekt.correspondence.slippages():
if not mapping.isNearlyContainedBy(result):
result += [mapping]
return result
def buildRule(self, rule):
if self.rule:
self.structures.remove(self.rule)
self.rule = rule
self.structures += [rule]
rule.activateRuleDescriptions()
def breakRule(self):
self.rule = None
def buildDescriptions(self, objekt):
for description in objekt.descriptions:
description.descriptionType.buffer = 100.0
#logging.info("Set buffer to 100 for " + description.descriptionType.get_name());
description.descriptor.buffer = 100.0
#logging.info("Set buffer to 100 for " + description.descriptor.get_name());
if description not in self.structures:
self.structures += [description]
workspace = Workspace()

160
workspaceFormulas.py Normal file
View File

@ -0,0 +1,160 @@
import logging
from workspace import workspace
from temperature import temperature
from slipnet import slipnet
import formulas
class WorkspaceFormulas(object):
def __init__(self):
self.clampTemperature = False
def updateTemperature(self):
logging.debug('updateTemperature')
workspace.assessTemperature()
ruleWeakness = 100.0
if workspace.rule:
workspace.rule.updateStrength()
ruleWeakness = 100.0 - workspace.rule.totalStrength
values = ( (workspace.totalUnhappiness, 0.8), (ruleWeakness, 0.2), )
slightly_above_actual_temperature = formulas.actualTemperature + 0.001
logging.info('actualTemperature: %f' % slightly_above_actual_temperature)
formulas.actualTemperature = formulas.weightedAverage(values)
logging.info('unhappiness: %f, weakness: %f, actualTemperature: %f' % (
workspace.totalUnhappiness + 0.001, ruleWeakness + 0.001, formulas.actualTemperature + 0.001))
if temperature.clamped:
formulas.actualTemperature = 100.0
logging.info('actualTemperature: %f' % (formulas.actualTemperature + 0.001))
temperature.update(formulas.actualTemperature)
if not self.clampTemperature:
formulas.Temperature = formulas.actualTemperature
temperature.update(formulas.Temperature)
workspaceFormulas = WorkspaceFormulas()
def numberOfObjects():
return len(workspace.objects)
def chooseUnmodifiedObject(attribute,inObjects):
objects = [ o for o in inObjects if o.string != workspace.modified ]
if not len(objects):
print 'no objects available in initial or target strings'
return formulas.chooseObjectFromList(objects,attribute)
def chooseNeighbour(source):
objects = []
for objekt in workspace.objects:
if objekt.string != source.string:
continue
if objekt.leftStringPosition == source.rightStringPosition + 1:
objects += [ objekt ]
elif source.leftStringPosition == objekt.rightStringPosition + 1:
objects += [ objekt ]
return formulas.chooseObjectFromList(objects,"intraStringSalience")
def chooseDirectedNeighbor(source,direction):
if direction == slipnet.left:
logging.info('Left')
return __chooseLeftNeighbor(source)
logging.info('Right')
return __chooseRightNeighbor(source)
def __chooseLeftNeighbor(source):
objects = []
for o in workspace.objects:
if o.string == source.string :
if source.leftStringPosition == o.rightStringPosition + 1:
logging.info('%s is on left of %s' % (o,source))
objects += [ o ]
else:
logging.info('%s is not on left of %s' % (o,source))
logging.info('Number of left objects: %s' % len(objects))
return formulas.chooseObjectFromList(objects,'intraStringSalience')
def __chooseRightNeighbor(source):
objects = [ o for o in workspace.objects if
o.string == source.string and
o.leftStringPosition == source.rightStringPosition + 1
]
return formulas.chooseObjectFromList(objects,'intraStringSalience')
def chooseBondFacet(source, destination):
sourceFacets = [ d.descriptionType for d in source.descriptions if d.descriptionType in slipnet.bondFacets ]
bondFacets = [ d.descriptionType for d in destination.descriptions if d.descriptionType in sourceFacets ]
if not bondFacets:
return None
supports = [ __supportForDescriptionType(f,source.string) for f in bondFacets ]
i = formulas.selectListPosition(supports)
return bondFacets[ i ]
def __supportForDescriptionType(descriptionType,string):
return ( descriptionType.activation + __descriptionTypeSupport(descriptionType,string) ) / 2
def __descriptionTypeSupport(descriptionType,string):
"""The proportion of objects in the string that have a description with this descriptionType"""
numberOfObjects = totalNumberOfObjects = 0.0
for objekt in workspace.objects:
if objekt.string == string:
totalNumberOfObjects += 1.0
for description in objekt.descriptions:
if description.descriptionType == descriptionType:
numberOfObjects += 1.0
return numberOfObjects / totalNumberOfObjects
def probabilityOfPosting(codeletName):
if codeletName == 'breaker':
return 1.0
if 'description' in codeletName:
result = ( formulas.Temperature / 100.0 ) ** 2
else:
result = workspace.intraStringUnhappiness / 100.0
if 'correspondence' in codeletName:
result = workspace.interStringUnhappiness / 100.0
if 'replacement' in codeletName:
if workspace.numberOfUnreplacedObjects() > 0:
return 1.0
return 0.0
if 'rule' in codeletName:
if not workspace.rule:
return 1.0
return workspace.rule.totalWeakness() / 100.0
if 'translator' in codeletName:
if not workspace.rule:
assert 0
return 0.0
assert 0
return 1.0
return result
def howManyToPost(codeletName):
if codeletName == 'breaker':
return 1
if 'description' in codeletName:
return 1
if 'translator' in codeletName:
if not workspace.rule:
return 0
return 1
if 'rule' in codeletName:
return 2
if 'group' in codeletName and not workspace.numberOfBonds():
return 0
if 'replacement' in codeletName and workspace.rule:
return 0
number = 0
if 'bond' in codeletName:
number = workspace.numberOfUnrelatedObjects()
# print 'post number of unrelated: %d, objects: %d' % (number,len(workspace.objects))
if 'group' in codeletName:
number = workspace.numberOfUngroupedObjects()
if 'replacement' in codeletName:
number = workspace.numberOfUnreplacedObjects()
if 'correspondence' in codeletName:
number = workspace.numberOfUncorrespondingObjects()
if number < formulas.blur(2.0):
return 1
if number < formulas.blur(4.0):
return 2
return 3

226
workspaceObject.py Normal file
View File

@ -0,0 +1,226 @@
import logging
from description import Description
from slipnet import slipnet
from workspaceStructure import WorkspaceStructure
class WorkspaceObject(WorkspaceStructure):
def __init__(self,workspaceString):
WorkspaceStructure.__init__(self)
self.string = workspaceString
#self.string.objects += [ self ]
self.descriptions = []
self.extrinsicDescriptions = []
self.incomingBonds = []
self.outgoingBonds = []
self.bonds = []
self.group = None
self.changed = None
self.correspondence = None
self.clampSalience = False
self.rawImportance = 0.0
self.relativeImportance = 0.0
self.leftBond = None
self.rightBond = None
self.newAnswerLetter = False
self.name = ''
self.replacement = None
self.rightStringPosition = 0
self.leftStringPosition = 0
self.leftmost = False
self.rightmost = False
self.intraStringSalience = 0.0
self.interStringSalience = 0.0
self.totalSalience = 0.0
self.intraStringUnhappiness = 0.0
self.interStringUnhappiness = 0.0
self.totalUnhappiness = 0.0
def __str__(self):
return 'object'
def spansString(self):
return self.leftmost and self.rightmost
def addDescription(self,descriptionType,descriptor):
description = Description(self,descriptionType,descriptor)
logging.info("Adding description: %s to %s" % (description,self))
self.descriptions += [ description ]
def addDescriptions(self,descriptions):
#print 'addDescriptions 1'
#print 'add %d to %d of %s' % (len(descriptions),len(self.descriptions), self.string.string)
copy = descriptions[:] # in case we add to our own descriptions, which turns the loop infinite
for description in copy:
#print '%d addDescriptions 2 %s ' % (len(descriptions),description)
logging.info('might add: %s' % description)
if not self.containsDescription(description):
#print '%d addDescriptions 3 %s ' % (len(descriptions),description)
self.addDescription(description.descriptionType,description.descriptor)
#print '%d addDescriptions 4 %s ' % (len(descriptions),description)
else:
logging.info("Won't add it")
#print '%d added, have %d ' % (len(descriptions),len(self.descriptions))
from workspace import workspace
workspace.buildDescriptions(self)
def __calculateIntraStringHappiness(self):
if self.spansString():
return 100.0
if self.group:
return self.group.totalStrength
bondStrength = 0.0
for bond in self.bonds:
bondStrength += bond.totalStrength
divisor = 6.0
if self.spansString(): # XXX then we have already returned
divisor = 3.0
return bondStrength / divisor
def __calculateRawImportance(self):
"""Calculate the raw importance of this object.
Which is the sum of all relevant descriptions"""
result = 0.0
for description in self.descriptions:
if description.descriptionType.fully_active():
result += description.descriptor.activation
else:
result += description.descriptor.activation / 20.0
if self.group:
result *= 2.0 / 3.0
if self.changed:
result *= 2.0
return result
def updateValue(self):
self.rawImportance = self.__calculateRawImportance()
intraStringHappiness = self.__calculateIntraStringHappiness()
self.intraStringUnhappiness = 100.0 - intraStringHappiness
interStringHappiness = 0.0
if self.correspondence:
interStringHappiness = self.correspondence.totalStrength
self.interStringUnhappiness = 100.0 - interStringHappiness
#logging.info("Unhappy: %s"%self.interStringUnhappiness)
averageHappiness = ( intraStringHappiness + interStringHappiness ) / 2
self.totalUnhappiness = 100.0 - averageHappiness
if self.clampSalience:
self.intraStringSalience = 100.0
self.interStringSalience = 100.0
else:
from formulas import weightedAverage
self.intraStringSalience = weightedAverage( ((self.relativeImportance,0.2), (self.intraStringUnhappiness,0.8)) )
self.interStringSalience = weightedAverage( ((self.relativeImportance,0.8), (self.interStringUnhappiness,0.2)) )
self.totalSalience = (self.intraStringSalience + self.interStringSalience) / 2.0
logging.info('Set salience of %s to %f = (%f + %f)/2' % (
self.__str__(),self.totalSalience, self.intraStringSalience, self.interStringSalience))
def isWithin(self,other):
return self.leftStringPosition >= other.leftStringPosition and self.rightStringPosition <= other.rightStringPosition
def relevantDescriptions(self):
return [ d for d in self.descriptions if d.descriptionType.fully_active() ]
def morePossibleDescriptions(self,node):
return []
def getPossibleDescriptions(self,descriptionType):
logging.info('getting possible descriptions for %s' % self)
descriptions = [ ]
from group import Group
for link in descriptionType.instanceLinks:
node = link.destination
if node == slipnet.first and self.hasDescription(slipnet.letters[0]):
descriptions += [ node ]
if node == slipnet.last and self.hasDescription(slipnet.letters[-1]):
descriptions += [ node ]
i = 1
for number in slipnet.numbers:
if node == number and isinstance(self,Group) and len(self.objectList) == i:
descriptions += [ node ]
i += 1
if node == slipnet.middle and self.middleObject():
descriptions += [ node ]
s = ''
for d in descriptions:
s = '%s, %s' % (s,d.get_name())
logging.info(s)
return descriptions
def containsDescription(self,sought):
soughtType = sought.descriptionType
soughtDescriptor = sought.descriptor
for d in self.descriptions:
if soughtType == d.descriptionType and soughtDescriptor == d.descriptor:
return True
return False
def hasDescription(self,slipnode):
return [ d for d in self.descriptions if d.descriptor == slipnode ] and True or False
def middleObject(self):
# XXX only works if string is 3 chars long
# as we have access to the string, why not just " == len / 2" ?
objectOnMyRightIsRightmost = objectOnMyLeftIsLeftmost = False
for objekt in self.string.objects:
if objekt.leftmost and objekt.rightStringPosition == self.leftStringPosition - 1:
objectOnMyLeftIsLeftmost = True
if objekt.rightmost and objekt.leftStringPosition == self.rightStringPosition + 1:
objectOnMyRightIsRightmost = True
return objectOnMyRightIsRightmost and objectOnMyLeftIsLeftmost
def distinguishingDescriptor(self,descriptor):
"""Whether no other object of the same type (ie. letter or group) has the same descriptor"""
if descriptor == slipnet.letter:
return False
if descriptor == slipnet.group:
return False
for number in slipnet.numbers:
if number == descriptor:
return False
return True
def relevantDistinguishingDescriptors(self):
return [ d.descriptor for d in self.relevantDescriptions() if self.distinguishingDescriptor(d.descriptor) ]
def getDescriptor(self,descriptionType):
"""The description attached to this object of the specified description type."""
descriptor = None
logging.info("\nIn %s, trying for type: %s" % (self,descriptionType.get_name()))
for description in self.descriptions:
logging.info("Trying description: %s" % description)
if description.descriptionType == descriptionType:
return description.descriptor
return descriptor
def getDescriptionType(self,sought_description):
"""The description_type attached to this object of the specified description"""
for description in self.descriptions:
if description.descriptor == sought_description:
return description.descriptionType
description = None
return description
def getCommonGroups(self,other):
return [ o for o in self.string.objects if self.isWithin(o) and other.isWithin(o) ]
def letterDistance(self,other):
if other.leftStringPosition > self.rightStringPosition:
return other.leftStringPosition - self.rightStringPosition
if self.leftStringPosition > other.rightStringPosition:
return self.leftStringPosition - other.rightStringPosition
return 0
def letterSpan(self):
return self.rightStringPosition - self.leftStringPosition + 1
def beside(self,other):
if self.string != other.string:
return False
if self.leftStringPosition == other.rightStringPosition + 1:
return True
return other.leftStringPosition == self.rightStringPosition + 1

80
workspaceString.py Normal file
View File

@ -0,0 +1,80 @@
import logging
from letter import Letter
from slipnet import slipnet
class WorkspaceString(object):
def __init__(self, s):
self.string = s
self.bonds = []
self.objects = []
self.letters = []
self.length = len(s)
self.intraStringUnhappiness = 0.0
if not self.length:
return
position = 0
from workspace import workspace
for c in self.string.upper():
value = ord(c) - ord('A')
letter = Letter(self, position + 1, self.length)
letter.workspaceString = self
letter.addDescription(slipnet.objectCategory, slipnet.letter)
letter.addDescription(slipnet.letterCategory, slipnet.letters[value])
letter.describe(position + 1, self.length)
workspace.buildDescriptions(letter)
self.letters += [letter]
position += 1
def __repr__(self):
return '<WorkspaceString: %s>' % self.string
def __str__(self):
return '%s with %d letters, %d objects, %d bonds' % (self.string, len(self.letters), len(self.objects), len(self.bonds))
def log(self, heading):
s = '%s: %s - ' % (heading, self)
for l in self.letters:
s += ' %s' % l
s += '; '
for o in self.objects:
s += ' %s' % o
s += '; '
for b in self.bonds:
s += ' %s' % b
s += '.'
logging.info(s)
def __len__(self):
return len(self.string)
def __getitem__(self, i):
return self.string[i]
def updateRelativeImportance(self):
"""Update the normalised importance of all objects in the string"""
total = sum([o.rawImportance for o in self.objects])
if not total:
for o in self.objects:
o.relativeImportance = 0.0
else:
for o in self.objects:
logging.info('object: %s, relative: %d = raw: %d / total: %d' % (
o, o.relativeImportance * 1000, o.rawImportance, total ))
o.relativeImportance = o.rawImportance / total
def updateIntraStringUnhappiness(self):
if not len(self.objects):
self.intraStringUnhappiness = 0.0
return
total = sum([o.intraStringUnhappiness for o in self.objects])
self.intraStringUnhappiness = total / len(self.objects)
def equivalentGroup(self, sought):
from group import Group
for objekt in self.objects:
if isinstance(objekt, Group):
if objekt.sameGroup(sought):
return objekt
return None

37
workspaceStructure.py Normal file
View File

@ -0,0 +1,37 @@
import formulas
class WorkspaceStructure(object):
def __init__(self):
self.string = None
self.internalStrength = 0.0
self.externalStrength = 0.0
self.totalStrength = 0.0
def updateStrength(self):
self.updateInternalStrength()
self.updateExternalStrength()
self.updateTotalStrength()
def updateTotalStrength(self):
"""Recalculate the total strength based on internal and external strengths"""
weights = ( (self.internalStrength, self.internalStrength), (self.externalStrength, 100 - self.internalStrength) )
strength = formulas.weightedAverage(weights)
self.totalStrength = strength
def totalWeakness(self):
"""The total weakness is derived from total strength"""
return 100 - self.totalStrength ** 0.95
def updateInternalStrength(self):
"""How internally cohesive the structure is"""
raise NotImplementedError, 'call of abstract method: WorkspaceStructure.updateInternalStrength()'
def updateExternalStrength(self):
raise NotImplementedError, 'call of abstract method: WorkspaceStructure.updateExternalStrength()'
def break_the_structure(self):
"""Break this workspace structure
Exactly what is broken depends on sub-class
"""
raise NotImplementedError, 'call of abstract method: WorkspaceStructure.break_the_structure()'