Fix a lot of crashes with empty or single-letter inputs.

This commit is contained in:
Arthur O'Dwyer
2017-05-03 02:01:57 -07:00
parent 2a48245c15
commit 318d0e2349
4 changed files with 30 additions and 18 deletions

View File

@ -267,6 +267,7 @@ def bottom_up_bond_scout(ctx, codelet):
slipnet = ctx.slipnet slipnet = ctx.slipnet
workspace = ctx.workspace workspace = ctx.workspace
source = chooseUnmodifiedObject(ctx, 'intraStringSalience', workspace.objects) source = chooseUnmodifiedObject(ctx, 'intraStringSalience', workspace.objects)
assert source is not None
__showWhichStringObjectIsFrom(source) __showWhichStringObjectIsFrom(source)
destination = chooseNeighbor(ctx, source) destination = chooseNeighbor(ctx, source)
assert destination assert destination
@ -372,14 +373,13 @@ def replacement_finder(ctx, codelet):
workspace = ctx.workspace workspace = ctx.workspace
# choose random letter in initial string # choose random letter in initial string
letters = [o for o in workspace.initial.objects if isinstance(o, Letter)] letters = [o for o in workspace.initial.objects if isinstance(o, Letter)]
assert letters
letterOfInitialString = random.choice(letters) letterOfInitialString = random.choice(letters)
if letterOfInitialString.replacement: assert not letterOfInitialString.replacement
return
position = letterOfInitialString.leftIndex position = letterOfInitialString.leftIndex
moreLetters = [o for o in workspace.modified.objects moreLetters = [o for o in workspace.modified.objects
if isinstance(o, Letter) and o.leftIndex == position] if isinstance(o, Letter) and o.leftIndex == position]
if not moreLetters: assert moreLetters
return
letterOfModifiedString = moreLetters[0] letterOfModifiedString = moreLetters[0]
initialAscii = ord(workspace.initialString[position - 1]) initialAscii = ord(workspace.initialString[position - 1])
modifiedAscii = ord(workspace.modifiedString[position - 1]) modifiedAscii = ord(workspace.modifiedString[position - 1])
@ -702,7 +702,8 @@ def group_scout__whole_string(ctx, codelet):
workspace = ctx.workspace workspace = ctx.workspace
string = random.choice([workspace.initial, workspace.target]) string = random.choice([workspace.initial, workspace.target])
# find leftmost object & the highest group to which it belongs # find leftmost object & the highest group to which it belongs
leftmost = next(o for o in string.objects if o.leftmost) leftmost = next((o for o in string.objects if o.leftmost), None)
assert leftmost is not None
while leftmost.group and leftmost.group.bondCategory == slipnet.sameness: while leftmost.group and leftmost.group.bondCategory == slipnet.sameness:
leftmost = leftmost.group leftmost = leftmost.group
if leftmost.spansString(): if leftmost.spansString():
@ -862,11 +863,10 @@ def rule_translator(ctx, codelet):
temperature = ctx.temperature temperature = ctx.temperature
workspace = ctx.workspace workspace = ctx.workspace
assert workspace.rule assert workspace.rule
if len(workspace.initial) == 1 and len(workspace.target) == 1: if len(workspace.initial) + len(workspace.target) <= 2:
bondDensity = 1.0 bondDensity = 1.0
else: else:
numberOfBonds = (len(workspace.initial.bonds) + numberOfBonds = len(workspace.initial.bonds) + len(workspace.target.bonds)
len(workspace.target.bonds))
nearlyTotalLength = len(workspace.initial) + len(workspace.target) - 2 nearlyTotalLength = len(workspace.initial) + len(workspace.target) - 2
bondDensity = numberOfBonds / nearlyTotalLength bondDensity = numberOfBonds / nearlyTotalLength
bondDensity = min(bondDensity, 1.0) bondDensity = min(bondDensity, 1.0)
@ -887,8 +887,10 @@ def bottom_up_correspondence_scout(ctx, codelet):
workspace = ctx.workspace workspace = ctx.workspace
objectFromInitial = chooseUnmodifiedObject(ctx, 'interStringSalience', objectFromInitial = chooseUnmodifiedObject(ctx, 'interStringSalience',
workspace.initial.objects) workspace.initial.objects)
assert objectFromInitial is not None
objectFromTarget = chooseUnmodifiedObject(ctx, 'interStringSalience', objectFromTarget = chooseUnmodifiedObject(ctx, 'interStringSalience',
workspace.target.objects) workspace.target.objects)
assert objectFromTarget is not None
assert objectFromInitial.spansString() == objectFromTarget.spansString() assert objectFromInitial.spansString() == objectFromTarget.spansString()
# get the posible concept mappings # get the posible concept mappings
conceptMappings = formulas.getMappings( conceptMappings = formulas.getMappings(
@ -930,6 +932,7 @@ def important_object_correspondence_scout(ctx, codelet):
workspace = ctx.workspace workspace = ctx.workspace
objectFromInitial = chooseUnmodifiedObject(ctx, 'relativeImportance', objectFromInitial = chooseUnmodifiedObject(ctx, 'relativeImportance',
workspace.initial.objects) workspace.initial.objects)
assert objectFromInitial is not None
descriptors = objectFromInitial.relevantDistinguishingDescriptors() descriptors = objectFromInitial.relevantDistinguishingDescriptors()
# choose descriptor by conceptual depth # choose descriptor by conceptual depth
weights = [temperature.getAdjustedValue(n.conceptualDepth) for n in descriptors] weights = [temperature.getAdjustedValue(n.conceptualDepth) for n in descriptors]

View File

@ -259,14 +259,20 @@ class Coderack(object):
def postInitialCodelets(self): def postInitialCodelets(self):
workspace = self.ctx.workspace workspace = self.ctx.workspace
logging.info("posting initial codelets") n = len(workspace.objects)
codeletsToPost = [ if n == 0:
'bottom-up-bond-scout', # The most pathological case.
'replacement-finder', codeletsToPost = [
'bottom-up-correspondence-scout', ('rule-scout', 1),
] ]
for name in codeletsToPost: else:
for _ in xrange(2 * len(workspace.objects)): codeletsToPost = [
('bottom-up-bond-scout', 2 * n),
('replacement-finder', 2 * n),
('bottom-up-correspondence-scout', 2 * n),
]
for name, count in codeletsToPost:
for _ in xrange(count):
codelet = Codelet(name, 1, [], self.codeletsRun) codelet = Codelet(name, 1, [], self.codeletsRun)
self.post(codelet) self.post(codelet)

View File

@ -370,7 +370,6 @@ class CursesReporter(Reporter):
for string in [workspace.initial, workspace.modified, workspace.target]: for string in [workspace.initial, workspace.modified, workspace.target]:
row += 1 row += 1
maxImportance = max(o.relativeImportance for o in group_and_letter_objects if o.string == string)
letters_in_string = sorted( letters_in_string = sorted(
(o for o in letter_objects if o.string == string), (o for o in letter_objects if o.string == string),
key=lambda o: o.leftIndex, key=lambda o: o.leftIndex,
@ -379,6 +378,8 @@ class CursesReporter(Reporter):
(o for o in group_objects if o.string == string), (o for o in group_objects if o.string == string),
key=lambda o: o.leftIndex, key=lambda o: o.leftIndex,
) )
if groups_in_string or letters_in_string:
maxImportance = max(o.relativeImportance for o in groups_in_string + letters_in_string)
bonds_in_string = sorted( bonds_in_string = sorted(
(b for b in bond_structures if b.string == string), (b for b in bond_structures if b.string == string),
key=lambda b: b.leftObject.rightIndex, key=lambda b: b.leftObject.rightIndex,

View File

@ -26,7 +26,7 @@ class Rule(WorkspaceStructure):
def updateInternalStrength(self): def updateInternalStrength(self):
workspace = self.ctx.workspace workspace = self.ctx.workspace
if not (self.descriptor and self.relation): if not (self.descriptor and self.relation):
self.internalStrength = 0.0 self.internalStrength = 50.0
return return
averageDepth = (self.descriptor.conceptualDepth + averageDepth = (self.descriptor.conceptualDepth +
self.relation.conceptualDepth) / 2.0 self.relation.conceptualDepth) / 2.0
@ -121,6 +121,8 @@ class Rule(WorkspaceStructure):
def buildTranslatedRule(self): def buildTranslatedRule(self):
workspace = self.ctx.workspace workspace = self.ctx.workspace
if not (self.descriptor and self.relation):
return workspace.targetString
slippages = workspace.slippages() slippages = workspace.slippages()
self.category = self.category.applySlippages(slippages) self.category = self.category.applySlippages(slippages)
self.facet = self.facet.applySlippages(slippages) self.facet = self.facet.applySlippages(slippages)