Files
copycat/copycat/codeletMethods.py

1125 lines
45 KiB
Python

import inspect
import logging
from . import formulas
from .workspaceFormulas import chooseDirectedNeighbor
from .workspaceFormulas import chooseNeighbor
from .workspaceFormulas import chooseUnmodifiedObject
from .workspaceObject import WorkspaceObject
from .letter import Letter
from .replacement import Replacement
from .group import Group
from .bond import Bond
from .correspondence import Correspondence
def codelet(name):
"""Decorator for otherwise-unused functions that are in fact used as codelet behaviors"""
def wrap(f):
# Verify that the decorated function has exactly two parameters:
# 1. ctx - the context object containing workspace, slipnet, etc.
# 2. codelet - the codelet instance itself
# The None values in the tuple represent: no default args, no *args, no **kwargs
assert tuple(inspect.getargspec(f)) == (['ctx', 'codelet'], None, None, None)
# Mark this function as a valid codelet method
f.is_codelet_method = True
# Store the codelet name
f.codelet_name = name
# Return the decorated function
return f
return wrap
# some methods common to the codelets
def __showWhichStringObjectIsFrom(structure):
if not structure:
return
workspace = structure.ctx.workspace
whence = 'other'
if isinstance(structure, WorkspaceObject):
whence = 'target'
if structure.string == workspace.initial:
whence = 'initial'
logging.info('object chosen = %s from %s string' % (structure, whence))
def __getScoutSource(ctx, slipnode, relevanceMethod, typeName):
random = ctx.random
workspace = ctx.workspace
initialRelevance = relevanceMethod(workspace.initial, slipnode)
targetRelevance = relevanceMethod(workspace.target, slipnode)
initialUnhappiness = workspace.initial.intraStringUnhappiness
targetUnhappiness = workspace.target.intraStringUnhappiness
logging.info('initial : relevance = %d, unhappiness=%d',
initialRelevance, int(initialUnhappiness))
logging.info('target : relevance = %d, unhappiness=%d',
targetRelevance, int(targetUnhappiness))
string = workspace.initial
initials = initialRelevance + initialUnhappiness
targets = targetRelevance + targetUnhappiness
if random.weighted_greater_than(targets, initials):
string = workspace.target
logging.info('target string selected: %s for %s',
workspace.target, typeName)
else:
logging.info('initial string selected: %s for %s',
workspace.initial, typeName)
source = chooseUnmodifiedObject(ctx, 'intraStringSalience', string.objects)
return source
def __getDescriptors(bondFacet, source, destination):
sourceDescriptor = source.getDescriptor(bondFacet)
destinationDescriptor = destination.getDescriptor(bondFacet)
assert sourceDescriptor and destinationDescriptor
return sourceDescriptor, destinationDescriptor
def __structureVsStructure(structure1, weight1, structure2, weight2):
"""Return true if the first structure comes out stronger than the second."""
ctx = structure1.ctx
random = ctx.random
# TODO: use entropy
temperature = ctx.temperature
structure1.updateStrength()
structure2.updateStrength()
# TODO: use entropy
weightedStrength1 = temperature.getAdjustedValue(
structure1.totalStrength * weight1)
# TODO: use entropy
weightedStrength2 = temperature.getAdjustedValue(
structure2.totalStrength * weight2)
return random.weighted_greater_than(weightedStrength1, weightedStrength2)
def __fight(structure, structureWeight, incompatibles, incompatibleWeight):
if not (incompatibles and len(incompatibles)):
return True
for incompatible in incompatibles:
if not __structureVsStructure(structure, structureWeight,
incompatible, incompatibleWeight):
logging.info('lost fight with %s', incompatible)
return False
logging.info('won fight with %s', incompatible)
return True
def __fightIncompatibles(incompatibles, structure, name,
structureWeight, incompatibleWeight):
if len(incompatibles):
if __fight(structure, structureWeight,
incompatibles, incompatibleWeight):
logging.info('broke the %s', name)
return True
logging.info('failed to break %s: Fizzle', name)
return False
logging.info('no incompatible %s', name)
return True
def __slippability(ctx, conceptMappings):
random = ctx.random
temperature = ctx.temperature
for mapping in conceptMappings:
slippiness = mapping.slippability() / 100.0
probabilityOfSlippage = temperature.getAdjustedProbability(slippiness)
if random.coinFlip(probabilityOfSlippage):
return True
return False
@codelet('breaker')
def breaker(ctx, codelet):
# From the original LISP:
'''
First decides probabilistically whether or not to fizzle, based on
temperature. Chooses a structure and random and decides probabilistically
whether or not to break it as a function of its total weakness.
If the structure is a bond in a group, have to break the group in
order to break the bond.
'''
random = ctx.random
temperature = ctx.temperature
workspace = ctx.workspace
probabilityOfFizzle = (100.0 - temperature.value()) / 100.0
if random.coinFlip(probabilityOfFizzle):
return
# choose a structure at random
structures = [s for s in workspace.structures if
isinstance(s, (Group, Bond, Correspondence))]
assert len(structures)
structure = random.choice(structures)
__showWhichStringObjectIsFrom(structure)
breakObjects = [structure]
if isinstance(structure, Bond):
if structure.source.group:
if structure.source.group == structure.destination.group:
breakObjects += [structure.source.group]
# Break all the objects or none of them; this matches the Java
# "all objects" means a bond and its group, if it has one.
for structure in breakObjects:
breakProbability = temperature.getAdjustedProbability(
structure.totalStrength / 100.0)
if random.coinFlip(breakProbability):
return
for structure in breakObjects:
structure.break_the_structure()
def chooseRelevantDescriptionByActivation(ctx, workspaceObject):
random = ctx.random
descriptions = workspaceObject.relevantDescriptions()
weights = [description.descriptor.activation for description in descriptions]
return random.weighted_choice(descriptions, weights)
def similarPropertyLinks(ctx, slip_node):
random = ctx.random
# TODO: use entropy
temperature = ctx.temperature
result = []
for slip_link in slip_node.propertyLinks:
association = slip_link.degreeOfAssociation() / 100.0
# TODO:use entropy
probability = temperature.getAdjustedProbability(association)
if random.coinFlip(probability):
result += [slip_link]
return result
@codelet('bottom-up-description-scout')
def bottom_up_description_scout(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
workspace = ctx.workspace
chosenObject = chooseUnmodifiedObject(ctx, 'totalSalience', workspace.objects)
assert chosenObject
__showWhichStringObjectIsFrom(chosenObject)
# choose relevant description by activation
descriptions = chosenObject.relevantDescriptions()
weights = [d.descriptor.activation for d in descriptions]
description = random.weighted_choice(descriptions, weights)
assert description
sliplinks = similarPropertyLinks(ctx, description.descriptor)
assert sliplinks
weights = [sliplink.degreeOfAssociation() * sliplink.destination.activation
for sliplink in sliplinks]
chosen = random.weighted_choice(sliplinks, weights)
chosenProperty = chosen.destination
coderack.proposeDescription(chosenObject, chosenProperty.category(),
chosenProperty)
@codelet('top-down-description-scout')
def top_down_description_scout(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
workspace = ctx.workspace
descriptionType = codelet.arguments[0]
chosenObject = chooseUnmodifiedObject(ctx, 'totalSalience', workspace.objects)
assert chosenObject
__showWhichStringObjectIsFrom(chosenObject)
descriptions = chosenObject.getPossibleDescriptions(descriptionType)
assert descriptions and len(descriptions)
weights = [n.activation for n in descriptions]
chosenProperty = random.weighted_choice(descriptions, weights)
coderack.proposeDescription(chosenObject, chosenProperty.category(),
chosenProperty)
@codelet('description-strength-tester')
def description_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
# TODO: use entropy
temperature = ctx.temperature
description = codelet.arguments[0]
description.descriptor.buffer = 100.0
description.updateStrength()
strength = description.totalStrength
# TODO: use entropy
probability = temperature.getAdjustedProbability(strength / 100.0)
assert random.coinFlip(probability)
coderack.newCodelet('description-builder', strength, [description])
@codelet('description-builder')
def description_builder(ctx, codelet):
workspace = ctx.workspace
description = codelet.arguments[0]
assert description.object in workspace.objects
if description.object.described(description.descriptor):
description.descriptionType.buffer = 100.0
description.descriptor.buffer = 100.0
else:
description.build()
def __supportForDescriptionType(ctx, descriptionType, string):
workspace = ctx.workspace
described_count = 0
total = 0
for o in workspace.objects:
if o.string == string:
total += 1
described_count += sum(1 for d in o.descriptions if d.descriptionType == descriptionType)
string_support = described_count / float(total)
return (descriptionType.activation + string_support) / 2
def __chooseBondFacet(ctx, source, destination):
random = ctx.random
slipnet = ctx.slipnet
# specify the descriptor types that bonds can form between
b = [
slipnet.letterCategory,
slipnet.length,
]
sourceFacets = [d.descriptionType for d in source.descriptions if d.descriptionType in b]
bondFacets = [d.descriptionType for d in destination.descriptions if d.descriptionType in sourceFacets]
supports = [__supportForDescriptionType(ctx, f, source.string) for f in bondFacets]
return random.weighted_choice(bondFacets, supports)
@codelet('bottom-up-bond-scout')
def bottom_up_bond_scout(ctx, codelet):
coderack = ctx.coderack
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
logging.info('destination: %s', destination)
bondFacet = __chooseBondFacet(ctx, source, destination)
assert bondFacet
logging.info('chosen bond facet: %s', bondFacet.get_name())
logging.info('Source: %s, destination: %s', source, destination)
bond_descriptors = __getDescriptors(bondFacet, source, destination)
sourceDescriptor, destinationDescriptor = bond_descriptors
logging.info("source descriptor: %s", sourceDescriptor.name.upper())
logging.info("destination descriptor: %s",
destinationDescriptor.name.upper())
category = sourceDescriptor.getBondCategory(destinationDescriptor)
assert category
if category == slipnet.identity:
category = slipnet.sameness
logging.info('proposing %s bond ', category.name)
coderack.proposeBond(source, destination, category, bondFacet,
sourceDescriptor, destinationDescriptor)
@codelet('rule-scout')
def rule_scout(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
# TODO: use entropy
temperature = ctx.temperature
workspace = ctx.workspace
assert workspace.numberOfUnreplacedObjects() == 0
changedObjects = [o for o in workspace.initial.objects if o.changed]
# assert len(changedObjects) < 2
# if there are no changed objects, propose a rule with no changes
if not changedObjects:
return coderack.proposeRule(None, None, None, None)
changed = changedObjects[-1]
# generate a list of distinguishing descriptions for the first object
# ie. string-position (left-,right-most,middle or whole) or letter category
# if it is the only one of its type in the string
objectList = []
position = changed.getDescriptor(slipnet.stringPositionCategory)
if position:
objectList += [position]
letter = changed.getDescriptor(slipnet.letterCategory)
otherObjectsOfSameLetter = [o for o in workspace.initial.objects
if not o != changed
and o.getDescriptionType(letter)]
if not len(otherObjectsOfSameLetter):
objectList += [letter]
# if this object corresponds to another object in the workspace
# objectList = the union of this and the distingushing descriptors
if changed.correspondence:
targetObject = changed.correspondence.objectFromTarget
newList = []
slippages = workspace.slippages()
for node in objectList:
node = node.applySlippages(slippages)
if targetObject.described(node):
if targetObject.distinguishingDescriptor(node):
newList += [node]
objectList = newList # surely this should be +=
# "union of this and distinguishing descriptors"
assert objectList
# use conceptual depth to choose a description
# TODO: use entropy
weights = [
temperature.getAdjustedValue(node.conceptualDepth)
for node in objectList
]
descriptor = random.weighted_choice(objectList, weights)
# choose the relation (change the leftmost object to "successor" or "d"
objectList = []
if changed.replacement.relation:
objectList += [changed.replacement.relation]
objectList += [changed.replacement.objectFromModified.getDescriptor(
slipnet.letterCategory)]
# TODO: use entropy
# use conceptual depth to choose a relation
weights = [
temperature.getAdjustedValue(node.conceptualDepth)
for node in objectList
]
relation = random.weighted_choice(objectList, weights)
coderack.proposeRule(slipnet.letterCategory, descriptor,
slipnet.letter, relation)
@codelet('rule-strength-tester')
def rule_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
# TODO: use entropy
temperature = ctx.temperature
rule = codelet.arguments[0]
rule.updateStrength()
# TODO: use entropy
probability = temperature.getAdjustedProbability(rule.totalStrength / 100.0)
if random.coinFlip(probability):
coderack.newCodelet('rule-builder', rule.totalStrength, [rule])
@codelet('replacement-finder')
def replacement_finder(ctx, codelet):
random = ctx.random
slipnet = ctx.slipnet
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)
assert not letterOfInitialString.replacement
position = letterOfInitialString.leftIndex
moreLetters = [o for o in workspace.modified.objects
if isinstance(o, Letter) and o.leftIndex == position]
assert moreLetters
letterOfModifiedString = moreLetters[0]
initialAscii = ord(workspace.initialString[position - 1])
modifiedAscii = ord(workspace.modifiedString[position - 1])
diff = initialAscii - modifiedAscii
if abs(diff) < 2:
relations = {
0: slipnet.sameness,
-1: slipnet.successor,
1: slipnet.predecessor
}
relation = relations[diff]
else:
relation = None
letterOfInitialString.replacement = Replacement(ctx, letterOfInitialString,
letterOfModifiedString, relation)
if relation != slipnet.sameness:
letterOfInitialString.changed = True
workspace.changedObject = letterOfInitialString
@codelet('top-down-bond-scout--category')
def top_down_bond_scout__category(ctx, codelet):
coderack = ctx.coderack
slipnet = ctx.slipnet
logging.info('top_down_bond_scout__category')
category = codelet.arguments[0]
source = __getScoutSource(ctx, category, formulas.localBondCategoryRelevance,
'bond')
destination = chooseNeighbor(ctx, source)
logging.info('source: %s, destination: %s', source, destination)
assert destination
bondFacet = __chooseBondFacet(ctx, source, destination)
assert bondFacet
sourceDescriptor, destinationDescriptor = __getDescriptors(
bondFacet, source, destination)
forwardBond = sourceDescriptor.getBondCategory(destinationDescriptor)
if forwardBond == slipnet.identity:
forwardBond = slipnet.sameness
backwardBond = slipnet.sameness
else:
backwardBond = destinationDescriptor.getBondCategory(sourceDescriptor)
assert category == forwardBond or category == backwardBond
if category == forwardBond:
coderack.proposeBond(source, destination, category,
bondFacet, sourceDescriptor,
destinationDescriptor)
else:
coderack.proposeBond(destination, source, category,
bondFacet, destinationDescriptor,
sourceDescriptor)
@codelet('top-down-bond-scout--direction')
def top_down_bond_scout__direction(ctx, codelet):
coderack = ctx.coderack
slipnet = ctx.slipnet
direction = codelet.arguments[0]
source = __getScoutSource(ctx, direction, formulas.localDirectionCategoryRelevance,
'bond')
destination = chooseDirectedNeighbor(ctx, source, direction)
assert destination
logging.info('to object: %s', destination)
bondFacet = __chooseBondFacet(ctx, source, destination)
assert bondFacet
sourceDescriptor, destinationDescriptor = __getDescriptors(
bondFacet, source, destination)
category = sourceDescriptor.getBondCategory(destinationDescriptor)
assert category
if category == slipnet.identity:
category = slipnet.sameness
coderack.proposeBond(source, destination, category, bondFacet,
sourceDescriptor, destinationDescriptor)
@codelet('bond-strength-tester')
def bond_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
# TODO: use entropy
temperature = ctx.temperature
bond = codelet.arguments[0]
__showWhichStringObjectIsFrom(bond)
bond.updateStrength()
strength = bond.totalStrength
# TODO: use entropy
probability = temperature.getAdjustedProbability(strength / 100.0)
logging.info('bond strength = %d for %s', strength, bond)
assert random.coinFlip(probability)
bond.facet.buffer = 100.0
bond.sourceDescriptor.buffer = 100.0
bond.destinationDescriptor.buffer = 100.0
logging.info("succeeded: posting bond-builder")
coderack.newCodelet('bond-builder', strength, [bond])
@codelet('bond-builder')
def bond_builder(ctx, codelet):
workspace = ctx.workspace
bond = codelet.arguments[0]
__showWhichStringObjectIsFrom(bond)
bond.updateStrength()
assert (bond.source in workspace.objects or
bond.destination in workspace.objects)
for stringBond in bond.string.bonds:
if bond.sameNeighbors(stringBond) and bond.sameCategories(stringBond):
if bond.directionCategory:
bond.directionCategory.buffer = 100.0
bond.category.buffer = 100.0
logging.info('already exists: activate descriptors & Fizzle')
return
incompatibleBonds = bond.getIncompatibleBonds()
logging.info('number of incompatibleBonds: %d', len(incompatibleBonds))
if len(incompatibleBonds):
logging.info('%s', incompatibleBonds[0])
assert __fightIncompatibles(incompatibleBonds, bond, 'bonds', 1.0, 1.0)
incompatibleGroups = bond.source.getCommonGroups(bond.destination)
assert __fightIncompatibles(incompatibleGroups, bond, 'groups', 1.0, 1.0)
# fight all incompatible correspondences
incompatibleCorrespondences = []
if bond.leftObject.leftmost or bond.rightObject.rightmost:
if bond.directionCategory:
incompatibleCorrespondences = bond.getIncompatibleCorrespondences()
if incompatibleCorrespondences:
logging.info("trying to break incompatible correspondences")
assert __fight(bond, 2.0, incompatibleCorrespondences, 3.0)
# assert __fightIncompatibles(incompatibleCorrespondences,
# bond, 'correspondences', 2.0, 3.0)
for incompatible in incompatibleBonds:
incompatible.break_the_structure()
for incompatible in incompatibleGroups:
incompatible.break_the_structure()
for incompatible in incompatibleCorrespondences:
incompatible.break_the_structure()
logging.info('building bond %s', bond)
bond.buildBond()
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
@codelet('top-down-group-scout--category')
def top_down_group_scout__category(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
groupCategory = codelet.arguments[0]
category = groupCategory.getRelatedNode(slipnet.bondCategory)
assert category
source = __getScoutSource(ctx, category, formulas.localBondCategoryRelevance,
'group')
assert source and not source.spansString()
if source.leftmost:
direction = slipnet.right
elif source.rightmost:
direction = slipnet.left
else:
direction = random.weighted_choice(
[slipnet.left, slipnet.right],
[slipnet.left.activation, slipnet.right.activation]
)
if direction == slipnet.left:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond or firstBond.category != category:
# check the other side of object
if direction == slipnet.right:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond or firstBond.category != category:
if category == slipnet.sameness and isinstance(source, Letter):
group = Group(source.string, slipnet.samenessGroup,
None, slipnet.letterCategory, [source], [])
probability = group.singleLetterGroupProbability()
if random.coinFlip(probability):
coderack.proposeSingleLetterGroup(source)
return
direction = firstBond.directionCategory
search = True
bondFacet = None
# find leftmost object in group with these bonds
while search:
search = False
if not source.leftBond:
continue
if source.leftBond.category != category:
continue
if source.leftBond.directionCategory != direction:
if source.leftBond.directionCategory:
continue
if not bondFacet or bondFacet == source.leftBond.facet:
bondFacet = source.leftBond.facet
direction = source.leftBond.directionCategory
source = source.leftBond.leftObject
search = True
# find rightmost object in group with these bonds
search = True
destination = source
while search:
search = False
if not destination.rightBond:
continue
if destination.rightBond.category != category:
continue
if destination.rightBond.directionCategory != direction:
if destination.rightBond.directionCategory:
continue
if not bondFacet or bondFacet == destination.rightBond.facet:
bondFacet = destination.rightBond.facet
direction = source.rightBond.directionCategory
destination = destination.rightBond.rightObject
search = True
assert destination != source
objects = [source]
bonds = []
while source != destination:
bonds += [source.rightBond]
objects += [source.rightBond.rightObject]
source = source.rightBond.rightObject
coderack.proposeGroup(objects, bonds, groupCategory,
direction, bondFacet)
@codelet('top-down-group-scout--direction')
def top_down_group_scout__direction(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
direction = codelet.arguments[0]
source = __getScoutSource(ctx, direction,
formulas.localDirectionCategoryRelevance,
'direction')
logging.info('source chosen = %s', source)
assert not source.spansString()
if source.leftmost:
mydirection = slipnet.right
elif source.rightmost:
mydirection = slipnet.left
else:
mydirection = random.weighted_choice(
[slipnet.left, slipnet.right],
[slipnet.left.activation, slipnet.right.activation]
)
if mydirection == slipnet.left:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond:
logging.info('no firstBond')
else:
logging.info('firstBond: %s', firstBond)
if firstBond and not firstBond.directionCategory:
direction = None
if not firstBond or firstBond.directionCategory != direction:
if mydirection == slipnet.right:
firstBond = source.leftBond
else:
firstBond = source.rightBond
if not firstBond:
logging.info('no firstBond2')
else:
logging.info('firstBond2: %s', firstBond)
if firstBond and not firstBond.directionCategory:
direction = None
assert firstBond and firstBond.directionCategory == direction
logging.info('possible group: %s', firstBond)
category = firstBond.category
assert category
groupCategory = category.getRelatedNode(slipnet.groupCategory)
logging.info('trying from %s to %s', source, category.name)
bondFacet = None
# find leftmost object in group with these bonds
search = True
while search:
search = False
if not source.leftBond:
continue
if source.leftBond.category != category:
continue
if source.leftBond.directionCategory != direction:
if source.leftBond.directionCategory:
continue
if not bondFacet or bondFacet == source.leftBond.facet:
bondFacet = source.leftBond.facet
direction = source.leftBond.directionCategory
source = source.leftBond.leftObject
search = True
destination = source
search = True
while search:
search = False
if not destination.rightBond:
continue
if destination.rightBond.category != category:
continue
if destination.rightBond.directionCategory != direction:
if destination.rightBond.directionCategory:
continue
if not bondFacet or bondFacet == destination.rightBond.facet:
bondFacet = destination.rightBond.facet
direction = source.rightBond.directionCategory
destination = destination.rightBond.rightObject
search = True
assert destination != source
logging.info('proposing group from %s to %s', source, destination)
objects = [source]
bonds = []
while source != destination:
bonds += [source.rightBond]
objects += [source.rightBond.rightObject]
source = source.rightBond.rightObject
coderack.proposeGroup(objects, bonds, groupCategory,
direction, bondFacet)
# noinspection PyStringFormat
@codelet('group-scout--whole-string')
def group_scout__whole_string(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
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), None)
assert leftmost is not None
while leftmost.group and leftmost.group.bondCategory == slipnet.sameness:
leftmost = leftmost.group
if leftmost.spansString():
# the object already spans the string - propose this object
if isinstance(leftmost, Group):
group = leftmost
coderack.proposeGroup(group.objectList, group.bondList,
group.groupCategory, group.directionCategory,
group.facet)
else:
coderack.proposeSingleLetterGroup(leftmost)
return
bonds = []
objects = [leftmost]
while leftmost.rightBond:
bonds += [leftmost.rightBond]
leftmost = leftmost.rightBond.rightObject
objects += [leftmost]
assert leftmost.rightmost
# choose a random bond from list
chosenBond = random.choice(bonds)
bonds = chosenBond.possibleGroupBonds(bonds)
assert bonds
category = chosenBond.category
groupCategory = category.getRelatedNode(slipnet.groupCategory)
directionCategory = chosenBond.directionCategory
bondFacet = chosenBond.facet
coderack.proposeGroup(objects, bonds, groupCategory, directionCategory, bondFacet)
@codelet('group-strength-tester')
def group_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
# TODO: use entropy
temperature = ctx.temperature
# update strength value of the group
group = codelet.arguments[0]
__showWhichStringObjectIsFrom(group)
group.updateStrength()
strength = group.totalStrength
# TODO: use entropy
probability = temperature.getAdjustedProbability(strength / 100.0)
if random.coinFlip(probability):
# it is strong enough - post builder & activate nodes
group.groupCategory.getRelatedNode(slipnet.bondCategory).buffer = 100.0
if group.directionCategory:
group.directionCategory.buffer = 100.0
coderack.newCodelet('group-builder', strength, [group])
@codelet('group-builder')
def group_builder(ctx, codelet):
slipnet = ctx.slipnet
workspace = ctx.workspace
# update strength value of the group
group = codelet.arguments[0]
__showWhichStringObjectIsFrom(group)
equivalent = group.string.equivalentGroup(group)
if equivalent:
logging.info('already exists...activate descriptors & fizzle')
group.activateDescriptions()
equivalent.addDescriptions(group.descriptions)
return
# check to see if all objects are still there
for o in group.objectList:
assert o in workspace.objects
# check to see if bonds are there of the same direction
incompatibleBonds = [] # incompatible bond list
if len(group.objectList) > 1:
previous = group.objectList[0]
for objekt in group.objectList[1:]:
leftBond = objekt.leftBond
if leftBond:
if leftBond.leftObject == previous:
continue
if leftBond.directionCategory == group.directionCategory:
continue
incompatibleBonds += [leftBond]
previous = objekt
next_object = group.objectList[-1]
for objekt in reversed(group.objectList[:-1]):
rightBond = objekt.rightBond
if rightBond:
if rightBond.rightObject == next_object:
continue
if rightBond.directionCategory == group.directionCategory:
continue
incompatibleBonds += [rightBond]
next_object = objekt
# if incompatible bonds exist - fight
group.updateStrength()
assert __fightIncompatibles(incompatibleBonds, group, 'bonds', 1.0, 1.0)
# fight incompatible groups
# fight all groups containing these objects
incompatibleGroups = group.getIncompatibleGroups()
assert __fightIncompatibles(incompatibleGroups, group, 'Groups', 1.0, 1.0)
for incompatible in incompatibleBonds:
incompatible.break_the_structure()
# create new bonds
group.bondList = []
for i in range(1, len(group.objectList)):
object1 = group.objectList[i - 1]
object2 = group.objectList[i]
if not object1.rightBond:
if group.directionCategory == slipnet.right:
source = object1
destination = object2
else:
source = object2
destination = object1
category = group.groupCategory.getRelatedNode(slipnet.bondCategory)
facet = group.facet
newBond = Bond(ctx, source, destination, category, facet,
source.getDescriptor(facet),
destination.getDescriptor(facet))
newBond.buildBond()
group.bondList += [object1.rightBond]
for incompatible in incompatibleGroups:
incompatible.break_the_structure()
group.buildGroup()
group.activateDescriptions()
logging.info('building group')
@codelet('rule-builder')
def rule_builder(ctx, codelet):
workspace = ctx.workspace
rule = codelet.arguments[0]
if rule.ruleEqual(workspace.rule):
rule.activateRuleDescriptions()
return
rule.updateStrength()
assert rule.totalStrength
# fight against other rules
if workspace.rule is not None:
assert __structureVsStructure(rule, 1.0, workspace.rule, 1.0)
workspace.buildRule(rule)
def __getCutoffWeights(bondDensity):
if bondDensity > 0.8:
return [5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
elif bondDensity > 0.6:
return [2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0]
elif bondDensity > 0.4:
return [1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0]
elif bondDensity > 0.2:
return [1.0, 1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0]
else:
return [1.0, 1.0, 1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0]
@codelet('rule-translator')
def rule_translator(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
# TODO: use entropy
temperature = ctx.temperature
workspace = ctx.workspace
assert workspace.rule
if len(workspace.initial) + len(workspace.target) <= 2:
bondDensity = 1.0
else:
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)
weights = __getCutoffWeights(bondDensity)
cutoff = 10.0 * random.weighted_choice(list(range(1, 11)), weights)
# TODO: use entropy
if cutoff >= temperature.actual_value:
result = workspace.rule.buildTranslatedRule()
if result is not None:
workspace.finalAnswer = result
else:
temperature.clampUntil(coderack.codeletsRun + 100)
@codelet('bottom-up-correspondence-scout')
def bottom_up_correspondence_scout(ctx, codelet):
coderack = ctx.coderack
slipnet = ctx.slipnet
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(
objectFromInitial, objectFromTarget,
objectFromInitial.relevantDescriptions(),
objectFromTarget.relevantDescriptions())
assert conceptMappings and __slippability(ctx, conceptMappings)
# find out if any are distinguishing
distinguishingMappings = [m for m in conceptMappings if m.distinguishing()]
assert distinguishingMappings
# if both objects span the strings, check to see if the
# string description needs to be flipped
opposites = [m for m in distinguishingMappings
if m.initialDescriptionType == slipnet.stringPositionCategory
and m.initialDescriptionType != slipnet.bondFacet]
initialDescriptionTypes = [m.initialDescriptionType for m in opposites]
flipTargetObject = False
if (objectFromInitial.spansString() and
objectFromTarget.spansString() and
slipnet.directionCategory in initialDescriptionTypes
and all(m.label == slipnet.opposite for m in opposites) # unreached?
and slipnet.opposite.activation != 100.0):
objectFromTarget = objectFromTarget.flippedVersion()
conceptMappings = formulas.getMappings(
objectFromInitial, objectFromTarget,
objectFromInitial.relevantDescriptions(),
objectFromTarget.relevantDescriptions())
flipTargetObject = True
coderack.proposeCorrespondence(objectFromInitial, objectFromTarget,
conceptMappings, flipTargetObject)
@codelet('important-object-correspondence-scout')
def important_object_correspondence_scout(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
# TODO: use entropy
temperature = ctx.temperature
workspace = ctx.workspace
objectFromInitial = chooseUnmodifiedObject(ctx, 'relativeImportance',
workspace.initial.objects)
assert objectFromInitial is not None
descriptors = objectFromInitial.relevantDistinguishingDescriptors()
# choose descriptor by conceptual depth
# TODO: use entropy
weights = [temperature.getAdjustedValue(n.conceptualDepth) for n in descriptors]
slipnode = random.weighted_choice(descriptors, weights)
assert slipnode
initialDescriptor = slipnode
for mapping in workspace.slippages():
if mapping.initialDescriptor == slipnode:
initialDescriptor = mapping.targetDescriptor
targetCandidates = []
for objekt in workspace.target.objects:
for description in objekt.relevantDescriptions():
if description.descriptor == initialDescriptor:
targetCandidates += [objekt]
assert targetCandidates
objectFromTarget = chooseUnmodifiedObject(ctx, 'interStringSalience',
targetCandidates)
assert objectFromInitial.spansString() == objectFromTarget.spansString()
# get the posible concept mappings
conceptMappings = formulas.getMappings(
objectFromInitial, objectFromTarget,
objectFromInitial.relevantDescriptions(),
objectFromTarget.relevantDescriptions())
assert conceptMappings and __slippability(ctx, conceptMappings)
# find out if any are distinguishing
distinguishingMappings = [m for m in conceptMappings if m.distinguishing()]
assert distinguishingMappings
# if both objects span the strings, check to see if the
# string description needs to be flipped
opposites = [m for m in distinguishingMappings
if m.initialDescriptionType == slipnet.stringPositionCategory
and m.initialDescriptionType != slipnet.bondFacet]
initialDescriptionTypes = [m.initialDescriptionType for m in opposites]
flipTargetObject = False
if (objectFromInitial.spansString()
and objectFromTarget.spansString()
and slipnet.directionCategory in initialDescriptionTypes
and all(m.label == slipnet.opposite for m in opposites) # unreached?
and slipnet.opposite.activation != 100.0):
objectFromTarget = objectFromTarget.flippedVersion()
conceptMappings = formulas.getMappings(
objectFromInitial, objectFromTarget,
objectFromInitial.relevantDescriptions(),
objectFromTarget.relevantDescriptions())
flipTargetObject = True
coderack.proposeCorrespondence(objectFromInitial, objectFromTarget,
conceptMappings, flipTargetObject)
@codelet('correspondence-strength-tester')
def correspondence_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
# TODO: use entropy
temperature = ctx.temperature
workspace = ctx.workspace
correspondence = codelet.arguments[0]
objectFromInitial = correspondence.objectFromInitial
objectFromTarget = correspondence.objectFromTarget
assert (objectFromInitial in workspace.objects and
(objectFromTarget in workspace.objects or
correspondence.flipTargetObject and
not workspace.target.equivalentGroup(
objectFromTarget.flipped_version())))
correspondence.updateStrength()
strength = correspondence.totalStrength
# TODO: use entropy
probability = temperature.getAdjustedProbability(strength / 100.0)
if random.coinFlip(probability):
# activate some concepts
for mapping in correspondence.conceptMappings:
mapping.initialDescriptionType.buffer = 100.0
mapping.initialDescriptor.buffer = 100.0
mapping.targetDescriptionType.buffer = 100.0
mapping.targetDescriptor.buffer = 100.0
coderack.newCodelet('correspondence-builder',
strength, [correspondence])
@codelet('correspondence-builder')
def correspondence_builder(ctx, codelet):
workspace = ctx.workspace
correspondence = codelet.arguments[0]
objectFromInitial = correspondence.objectFromInitial
objectFromTarget = correspondence.objectFromTarget
wantFlip = correspondence.flipTargetObject
if wantFlip:
flipper = objectFromTarget.flippedVersion()
targetNotFlipped = not workspace.target.equivalentGroup(flipper)
else:
targetNotFlipped = False
initialInObjects = objectFromInitial in workspace.objects
targetInObjects = objectFromTarget in workspace.objects
assert (initialInObjects or (
not targetInObjects and (not (wantFlip and targetNotFlipped))))
if correspondence.reflexive():
# if the correspondence exists, activate concept mappings
# and add new ones to the existing corr.
existing = correspondence.objectFromInitial.correspondence
for mapping in correspondence.conceptMappings:
if mapping.label:
mapping.label.buffer = 100.0
if not mapping.isContainedBy(existing.conceptMappings):
existing.conceptMappings += [mapping]
return
incompatibles = correspondence.getIncompatibleCorrespondences()
# fight against all correspondences
if incompatibles:
correspondenceSpans = (correspondence.objectFromInitial.letterSpan() +
correspondence.objectFromTarget.letterSpan())
for incompatible in incompatibles:
incompatibleSpans = (incompatible.objectFromInitial.letterSpan() +
incompatible.objectFromTarget.letterSpan())
assert __structureVsStructure(correspondence, correspondenceSpans,
incompatible, incompatibleSpans)
incompatibleBond = None
incompatibleGroup = None
# if there is an incompatible bond then fight against it
initial = correspondence.objectFromInitial
target = correspondence.objectFromTarget
if (initial.leftmost or initial.rightmost and
target.leftmost or target.rightmost):
# search for the incompatible bond
incompatibleBond = correspondence.getIncompatibleBond()
if incompatibleBond:
# bond found - fight against it
assert __structureVsStructure(correspondence, 3.0,
incompatibleBond, 2.0)
# won against incompatible bond
incompatibleGroup = target.group
if incompatibleGroup:
assert __structureVsStructure(correspondence, 1.0,
incompatibleGroup, 1.0)
# if there is an incompatible rule, fight against it
incompatibleRule = None
if workspace.rule:
if workspace.rule.incompatibleRuleCorrespondence(correspondence):
incompatibleRule = workspace.rule
assert __structureVsStructure(correspondence, 1.0,
incompatibleRule, 1.0)
for incompatible in incompatibles:
incompatible.break_the_structure()
# break incompatible group and bond if they exist
if incompatibleBond:
incompatibleBond.break_the_structure()
if incompatibleGroup:
incompatibleGroup.break_the_structure()
if incompatibleRule:
workspace.breakRule()
correspondence.buildCorrespondence()