Files
copycat/copycat/rule.py
2017-07-31 17:08:26 -06:00

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:]