150 lines
5.9 KiB
Python
150 lines
5.9 KiB
Python
import logging
|
|
|
|
|
|
from .workspaceStructure import WorkspaceStructure
|
|
from . import formulas
|
|
|
|
|
|
class Rule(WorkspaceStructure):
|
|
def __init__(self, ctx, facet, descriptor, category, relation):
|
|
WorkspaceStructure.__init__(self, ctx)
|
|
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):
|
|
workspace = self.ctx.workspace
|
|
if not (self.descriptor and self.relation):
|
|
self.internalStrength = 50.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.described(slipnode):
|
|
self.internalStrength = 0.0
|
|
return
|
|
sharedDescriptorTerm = 100.0
|
|
conceptual_height = (100.0 - self.descriptor.conceptualDepth) / 10.0
|
|
sharedDescriptorWeight = conceptual_height ** 1.4
|
|
depthDifference = 100.0 - abs(self.descriptor.conceptualDepth -
|
|
self.relation.conceptualDepth)
|
|
weights = ((depthDifference, 12),
|
|
(averageDepth, 18),
|
|
(sharedDescriptorTerm, sharedDescriptorWeight))
|
|
self.internalStrength = formulas.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):
|
|
workspace = self.ctx.workspace
|
|
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
|
|
return any(m.initialDescriptor == self.descriptor
|
|
for m in correspondence.conceptMappings)
|
|
|
|
def __changeString(self, string):
|
|
slipnet = self.ctx.slipnet
|
|
# applies the changes to self string ie. successor
|
|
if self.facet == slipnet.length:
|
|
if self.relation == slipnet.predecessor:
|
|
return string[:-1]
|
|
elif self.relation == slipnet.successor:
|
|
# This seems to be happening at the wrong level of abstraction.
|
|
# "Lengthening" is not an operation that makes sense on strings;
|
|
# it makes sense only on *groups*, and here we've lost the
|
|
# "groupiness" of this string. What gives?
|
|
return string + string[0]
|
|
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):
|
|
workspace = self.ctx.workspace
|
|
if not (self.descriptor and self.relation):
|
|
return workspace.targetString
|
|
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
|
|
changeds = [o for o in workspace.target.objects if
|
|
o.described(self.descriptor) and
|
|
o.described(self.category)]
|
|
if len(changeds) == 0:
|
|
return workspace.targetString
|
|
elif len(changeds) > 1:
|
|
logging.info("More than one letter changed. Sorry, I can't solve problems like this right now.")
|
|
return None
|
|
else:
|
|
changed = changeds[0]
|
|
logging.debug('changed object = %s', changed)
|
|
left = changed.leftIndex - 1
|
|
right = changed.rightIndex
|
|
s = workspace.targetString
|
|
changed_middle = self.__changeString(s[left:right])
|
|
if changed_middle is None:
|
|
return None
|
|
return s[:left] + changed_middle + s[right:]
|