From 318d0e2349f879b5874ce9e97c6eb1d655019fc9 Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Wed, 3 May 2017 02:01:57 -0700 Subject: [PATCH] Fix a lot of crashes with empty or single-letter inputs. --- copycat/codeletMethods.py | 19 +++++++++++-------- copycat/coderack.py | 22 ++++++++++++++-------- copycat/curses_reporter.py | 3 ++- copycat/rule.py | 4 +++- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/copycat/codeletMethods.py b/copycat/codeletMethods.py index babda48..5cc09b1 100644 --- a/copycat/codeletMethods.py +++ b/copycat/codeletMethods.py @@ -267,6 +267,7 @@ def bottom_up_bond_scout(ctx, codelet): slipnet = ctx.slipnet workspace = ctx.workspace source = chooseUnmodifiedObject(ctx, 'intraStringSalience', workspace.objects) + assert source is not None __showWhichStringObjectIsFrom(source) destination = chooseNeighbor(ctx, source) assert destination @@ -372,14 +373,13 @@ def replacement_finder(ctx, codelet): workspace = ctx.workspace # choose random letter in initial string letters = [o for o in workspace.initial.objects if isinstance(o, Letter)] + assert letters letterOfInitialString = random.choice(letters) - if letterOfInitialString.replacement: - return + assert not letterOfInitialString.replacement position = letterOfInitialString.leftIndex moreLetters = [o for o in workspace.modified.objects if isinstance(o, Letter) and o.leftIndex == position] - if not moreLetters: - return + assert moreLetters letterOfModifiedString = moreLetters[0] initialAscii = ord(workspace.initialString[position - 1]) modifiedAscii = ord(workspace.modifiedString[position - 1]) @@ -702,7 +702,8 @@ def group_scout__whole_string(ctx, codelet): workspace = ctx.workspace string = random.choice([workspace.initial, workspace.target]) # 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: leftmost = leftmost.group if leftmost.spansString(): @@ -862,11 +863,10 @@ def rule_translator(ctx, codelet): temperature = ctx.temperature workspace = ctx.workspace assert workspace.rule - if len(workspace.initial) == 1 and len(workspace.target) == 1: + if len(workspace.initial) + len(workspace.target) <= 2: bondDensity = 1.0 else: - numberOfBonds = (len(workspace.initial.bonds) + - len(workspace.target.bonds)) + numberOfBonds = len(workspace.initial.bonds) + len(workspace.target.bonds) nearlyTotalLength = len(workspace.initial) + len(workspace.target) - 2 bondDensity = numberOfBonds / nearlyTotalLength bondDensity = min(bondDensity, 1.0) @@ -887,8 +887,10 @@ def bottom_up_correspondence_scout(ctx, codelet): workspace = ctx.workspace objectFromInitial = chooseUnmodifiedObject(ctx, 'interStringSalience', workspace.initial.objects) + assert objectFromInitial is not None objectFromTarget = chooseUnmodifiedObject(ctx, 'interStringSalience', workspace.target.objects) + assert objectFromTarget is not None assert objectFromInitial.spansString() == objectFromTarget.spansString() # get the posible concept mappings conceptMappings = formulas.getMappings( @@ -930,6 +932,7 @@ def important_object_correspondence_scout(ctx, codelet): workspace = ctx.workspace objectFromInitial = chooseUnmodifiedObject(ctx, 'relativeImportance', workspace.initial.objects) + assert objectFromInitial is not None descriptors = objectFromInitial.relevantDistinguishingDescriptors() # choose descriptor by conceptual depth weights = [temperature.getAdjustedValue(n.conceptualDepth) for n in descriptors] diff --git a/copycat/coderack.py b/copycat/coderack.py index 43754a5..cad5360 100644 --- a/copycat/coderack.py +++ b/copycat/coderack.py @@ -259,14 +259,20 @@ class Coderack(object): def postInitialCodelets(self): workspace = self.ctx.workspace - logging.info("posting initial codelets") - codeletsToPost = [ - 'bottom-up-bond-scout', - 'replacement-finder', - 'bottom-up-correspondence-scout', - ] - for name in codeletsToPost: - for _ in xrange(2 * len(workspace.objects)): + n = len(workspace.objects) + if n == 0: + # The most pathological case. + codeletsToPost = [ + ('rule-scout', 1), + ] + else: + 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) self.post(codelet) diff --git a/copycat/curses_reporter.py b/copycat/curses_reporter.py index 87ffc0b..b2f7bf8 100644 --- a/copycat/curses_reporter.py +++ b/copycat/curses_reporter.py @@ -370,7 +370,6 @@ class CursesReporter(Reporter): for string in [workspace.initial, workspace.modified, workspace.target]: row += 1 - maxImportance = max(o.relativeImportance for o in group_and_letter_objects if o.string == string) letters_in_string = sorted( (o for o in letter_objects if o.string == string), key=lambda o: o.leftIndex, @@ -379,6 +378,8 @@ class CursesReporter(Reporter): (o for o in group_objects if o.string == string), 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( (b for b in bond_structures if b.string == string), key=lambda b: b.leftObject.rightIndex, diff --git a/copycat/rule.py b/copycat/rule.py index 522cdbe..bc8526a 100644 --- a/copycat/rule.py +++ b/copycat/rule.py @@ -26,7 +26,7 @@ class Rule(WorkspaceStructure): def updateInternalStrength(self): workspace = self.ctx.workspace if not (self.descriptor and self.relation): - self.internalStrength = 0.0 + self.internalStrength = 50.0 return averageDepth = (self.descriptor.conceptualDepth + self.relation.conceptualDepth) / 2.0 @@ -121,6 +121,8 @@ class Rule(WorkspaceStructure): 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)