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