Major overhaul of "randomness" throughout.

- Nobody does `import random` anymore.

- Random numbers are gotten from `ctx.random`, which is an object
of type `Randomness` with all the convenience methods that used to
be obnoxious functions in the `formulas` module.

- Every place that was using `random.random()` to implement the
equivalent of Python3 `random.choices(seq, weights)` has been updated
to use `ctx.random.weighted_choice(seq, weights)`.

This has a functional effect, since the details of random number
generation have changed. The *statistical* effect should be small.
I do observe that Copycat is having trouble inventing the "mrrjjjj"
solution right now (even in 1000 test runs), so maybe something is
slightly broken.
This commit is contained in:
Arthur O'Dwyer
2017-04-17 22:18:37 -07:00
parent 8fdb9d06e6
commit 3732ae8475
11 changed files with 179 additions and 214 deletions

View File

@ -1,6 +1,5 @@
import inspect
import logging
import random
import formulas
from workspaceFormulas import chooseDirectedNeighbor
@ -37,7 +36,9 @@ def __showWhichStringObjectIsFrom(structure):
#print 'object chosen = %s from %s string' % (structure, whence)
def __getScoutSource(workspace, slipnode, relevanceMethod, typeName):
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
@ -47,11 +48,9 @@ def __getScoutSource(workspace, slipnode, relevanceMethod, typeName):
logging.info('target : relevance = %d, unhappiness=%d',
targetRelevance, int(targetUnhappiness))
string = workspace.initial
relevances = initialRelevance + targetRelevance
unhappinesses = initialUnhappiness + targetUnhappiness
randomized = random.random() * (relevances + unhappinesses)
initials = initialRelevance + initialUnhappiness
if randomized > initials:
targets = targetRelevance + targetUnhappiness
if random.weighted_greater_than(targets, initials):
string = workspace.target
logging.info('target string selected: %s for %s',
workspace.target, typeName)
@ -76,7 +75,9 @@ def __getDescriptors(bondFacet, source, destination):
def __structureVsStructure(structure1, weight1, structure2, weight2):
"""Return true if the first structure comes out stronger than the second."""
ctx = structure1.ctx
random = ctx.random
temperature = ctx.temperature
structure1.updateStrength()
structure2.updateStrength()
@ -84,9 +85,7 @@ def __structureVsStructure(structure1, weight1, structure2, weight2):
structure1.totalStrength * weight1)
weightedStrength2 = temperature.getAdjustedValue(
structure2.totalStrength * weight2)
rhs = (weightedStrength1 + weightedStrength2) * random.random()
logging.info('%d > %d', weightedStrength1, rhs)
return weightedStrength1 > rhs
return random.weighted_greater_than(weightedStrength1, weightedStrength2)
def __fight(structure, structureWeight, incompatibles, incompatibleWeight):
@ -115,21 +114,23 @@ def __fightIncompatibles(incompatibles, structure, name,
def __slippability(ctx, conceptMappings):
random = ctx.random
temperature = ctx.temperature
for mapping in conceptMappings:
slippiness = mapping.slippability() / 100.0
probabilityOfSlippage = temperature.getAdjustedProbability(slippiness)
if formulas.coinFlip(probabilityOfSlippage):
if random.coinFlip(probabilityOfSlippage):
return True
return False
@codelet('breaker')
def breaker(ctx, codelet):
random = ctx.random
temperature = ctx.temperature
workspace = ctx.workspace
probabilityOfFizzle = (100.0 - temperature.value()) / 100.0
if formulas.coinFlip(probabilityOfFizzle):
if random.coinFlip(probabilityOfFizzle):
return
# choose a structure at random
structures = [s for s in workspace.structures if
@ -146,18 +147,28 @@ def breaker(ctx, codelet):
for structure in breakObjects:
breakProbability = temperature.getAdjustedProbability(
structure.totalStrength / 100.0)
if formulas.coinFlip(breakProbability):
if random.coinFlip(breakProbability):
return
for structure in breakObjects:
structure.break_the_structure()
def similarPropertyLinks(slip_node, temperature):
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
temperature = ctx.temperature
result = []
for slip_link in slip_node.propertyLinks:
association = slip_link.degreeOfAssociation() / 100.0
probability = temperature.getAdjustedProbability(association)
if formulas.coinFlip(probability):
if random.coinFlip(probability):
result += [slip_link]
return result
@ -165,19 +176,21 @@ def similarPropertyLinks(slip_node, temperature):
@codelet('bottom-up-description-scout')
def bottom_up_description_scout(ctx, codelet):
coderack = ctx.coderack
temperature = ctx.temperature
random = ctx.random
workspace = ctx.workspace
chosenObject = chooseUnmodifiedObject('totalSalience', workspace.objects)
assert chosenObject
__showWhichStringObjectIsFrom(chosenObject)
description = formulas.chooseRelevantDescriptionByActivation(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(description.descriptor, temperature)
sliplinks = similarPropertyLinks(ctx, description.descriptor)
assert sliplinks
values = [sliplink.degreeOfAssociation() * sliplink.destination.activation
weights = [sliplink.degreeOfAssociation() * sliplink.destination.activation
for sliplink in sliplinks]
i = formulas.selectListPosition(values)
chosen = sliplinks[i]
chosen = random.weighted_choice(sliplinks, weights)
chosenProperty = chosen.destination
coderack.proposeDescription(chosenObject, chosenProperty.category(),
chosenProperty, codelet)
@ -186,6 +199,7 @@ def bottom_up_description_scout(ctx, codelet):
@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('totalSalience', workspace.objects)
@ -193,9 +207,8 @@ def top_down_description_scout(ctx, codelet):
__showWhichStringObjectIsFrom(chosenObject)
descriptions = chosenObject.getPossibleDescriptions(descriptionType)
assert descriptions and len(descriptions)
values = [n.activation for n in descriptions]
i = formulas.selectListPosition(values)
chosenProperty = descriptions[i]
weights = [n.activation for n in descriptions]
chosenProperty = random.weighted_choice(descriptions, weights)
coderack.proposeDescription(chosenObject, chosenProperty.category(),
chosenProperty, codelet)
@ -203,13 +216,14 @@ def top_down_description_scout(ctx, codelet):
@codelet('description-strength-tester')
def description_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
temperature = ctx.temperature
description = codelet.arguments[0]
description.descriptor.buffer = 100.0
description.updateStrength()
strength = description.totalStrength
probability = temperature.getAdjustedProbability(strength / 100.0)
assert formulas.coinFlip(probability)
assert random.coinFlip(probability)
coderack.newCodelet('description-builder', codelet, strength)
@ -255,6 +269,7 @@ def bottom_up_bond_scout(ctx, codelet):
@codelet('rule-scout')
def rule_scout(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
temperature = ctx.temperature
workspace = ctx.workspace
@ -292,15 +307,13 @@ def rule_scout(ctx, codelet):
newList += [node]
objectList = newList # surely this should be +=
# "union of this and distinguishing descriptors"
assert objectList and len(objectList)
assert objectList
# use conceptual depth to choose a description
valueList = []
for node in objectList:
depth = node.conceptualDepth
value = temperature.getAdjustedValue(depth)
valueList += [value]
i = formulas.selectListPosition(valueList)
descriptor = objectList[i]
weights = [
temperature.getAdjustedValue(node.conceptualDepth)
for node in objectList
]
descriptor = random.weighted_choice(objectList, weights)
# choose the relation (change the letmost object to "successor" or "d"
objectList = []
if changed.replacement.relation:
@ -308,13 +321,11 @@ def rule_scout(ctx, codelet):
objectList += [changed.replacement.objectFromModified.getDescriptor(
slipnet.letterCategory)]
# use conceptual depth to choose a relation
valueList = []
for node in objectList:
depth = node.conceptualDepth
value = temperature.getAdjustedValue(depth)
valueList += [value]
i = formulas.selectListPosition(valueList)
relation = objectList[i]
weights = [
temperature.getAdjustedValue(node.conceptualDepth)
for node in objectList
]
relation = random.weighted_choice(objectList, weights)
coderack.proposeRule(slipnet.letterCategory, descriptor,
slipnet.letter, relation, codelet)
@ -322,16 +333,18 @@ def rule_scout(ctx, codelet):
@codelet('rule-strength-tester')
def rule_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
temperature = ctx.temperature
rule = codelet.arguments[0]
rule.updateStrength()
probability = temperature.getAdjustedProbability(rule.totalStrength / 100.0)
if formulas.coinFlip(probability):
if random.coinFlip(probability):
coderack.newCodelet('rule-builder', codelet, 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
@ -374,10 +387,9 @@ def replacement_finder(ctx, codelet):
def top_down_bond_scout__category(ctx, codelet):
coderack = ctx.coderack
slipnet = ctx.slipnet
workspace = ctx.workspace
logging.info('top_down_bond_scout__category')
category = codelet.arguments[0]
source = __getScoutSource(workspace, category, formulas.localBondCategoryRelevance,
source = __getScoutSource(ctx, category, formulas.localBondCategoryRelevance,
'bond')
destination = chooseNeighbor(source)
logging.info('source: %s, destination: %s', source, destination)
@ -406,9 +418,8 @@ def top_down_bond_scout__category(ctx, codelet):
def top_down_bond_scout__direction(ctx, codelet):
coderack = ctx.coderack
slipnet = ctx.slipnet
workspace = ctx.workspace
direction = codelet.arguments[0]
source = __getScoutSource(workspace,
source = __getScoutSource(ctx,
direction, formulas.localDirectionCategoryRelevance, 'bond')
destination = chooseDirectedNeighbor(source, direction)
assert destination
@ -427,6 +438,7 @@ def top_down_bond_scout__direction(ctx, codelet):
@codelet('bond-strength-tester')
def bond_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
temperature = ctx.temperature
bond = codelet.arguments[0]
__showWhichStringObjectIsFrom(bond)
@ -434,7 +446,7 @@ def bond_strength_tester(ctx, codelet):
strength = bond.totalStrength
probability = temperature.getAdjustedProbability(strength / 100.0)
logging.info('bond strength = %d for %s', strength, bond)
assert formulas.coinFlip(probability)
assert random.coinFlip(probability)
bond.facet.buffer = 100.0
bond.sourceDescriptor.buffer = 100.0
bond.destinationDescriptor.buffer = 100.0
@ -489,12 +501,12 @@ def bond_builder(ctx, codelet):
@codelet('top-down-group-scout--category')
def top_down_group_scout__category(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
workspace = ctx.workspace
groupCategory = codelet.arguments[0]
category = groupCategory.getRelatedNode(slipnet.bondCategory)
assert category
source = __getScoutSource(workspace, category, formulas.localBondCategoryRelevance,
source = __getScoutSource(ctx, category, formulas.localBondCategoryRelevance,
'group')
assert source and not source.spansString()
if source.leftmost:
@ -502,11 +514,10 @@ def top_down_group_scout__category(ctx, codelet):
elif source.rightmost:
direction = slipnet.left
else:
activations = [slipnet.left.activation, slipnet.right.activation]
if not formulas.selectListPosition(activations):
direction = slipnet.left
else:
direction = slipnet.right
direction = random.weighted_choice(
[slipnet.left, slipnet.right],
[slipnet.left.activation, slipnet.right.activation]
)
if direction == slipnet.left:
firstBond = source.leftBond
else:
@ -522,7 +533,7 @@ def top_down_group_scout__category(ctx, codelet):
group = Group(source.string, slipnet.samenessGroup,
None, slipnet.letterCategory, [source], [])
probability = group.singleLetterGroupProbability()
if formulas.coinFlip(probability):
if random.coinFlip(probability):
coderack.proposeSingleLetterGroup(source, codelet)
return
direction = firstBond.directionCategory
@ -574,10 +585,10 @@ def top_down_group_scout__category(ctx, codelet):
@codelet('top-down-group-scout--direction')
def top_down_group_scout__direction(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
workspace = ctx.workspace
direction = codelet.arguments[0]
source = __getScoutSource(workspace, direction,
source = __getScoutSource(ctx, direction,
formulas.localDirectionCategoryRelevance,
'direction')
logging.info('source chosen = %s', source)
@ -587,12 +598,10 @@ def top_down_group_scout__direction(ctx, codelet):
elif source.rightmost:
mydirection = slipnet.left
else:
activations = [slipnet.left.activation]
activations += [slipnet.right.activation]
if not formulas.selectListPosition(activations):
mydirection = slipnet.left
else:
mydirection = slipnet.right
mydirection = random.weighted_choice(
[slipnet.left, slipnet.right],
[slipnet.left.activation, slipnet.right.activation]
)
if mydirection == slipnet.left:
firstBond = source.leftBond
else:
@ -669,9 +678,10 @@ def top_down_group_scout__direction(ctx, codelet):
@codelet('group-scout--whole-string')
def group_scout__whole_string(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
workspace = ctx.workspace
if formulas.coinFlip():
if random.coinFlip():
string = workspace.target
logging.info('target string selected: %s', workspace.target)
else:
@ -713,6 +723,7 @@ def group_scout__whole_string(ctx, codelet):
@codelet('group-strength-tester')
def group_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
temperature = ctx.temperature
# update strength value of the group
@ -721,7 +732,7 @@ def group_strength_tester(ctx, codelet):
group.updateStrength()
strength = group.totalStrength
probability = temperature.getAdjustedProbability(strength / 100.0)
if formulas.coinFlip(probability):
if random.coinFlip(probability):
# it is strong enough - post builder & activate nodes
group.groupCategory.getRelatedNode(slipnet.bondCategory).buffer = 100.0
if group.directionCategory:
@ -821,29 +832,23 @@ def rule_builder(ctx, codelet):
workspace.buildRule(rule)
def __getCutOff(density):
if density > 0.8:
distribution = [5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
elif density > 0.6:
distribution = [2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0]
elif density > 0.4:
distribution = [1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0]
elif density > 0.2:
distribution = [1.0, 1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0]
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:
distribution = [1.0, 1.0, 1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0]
stop = sum(distribution) * random.random()
total = 0.0
for i in xrange(len(distribution)):
total += distribution[i]
if total >= stop:
return i + 1
return len(distribution)
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
temperature = ctx.temperature
workspace = ctx.workspace
assert workspace.rule
@ -854,9 +859,9 @@ def rule_translator(ctx, codelet):
len(workspace.target.bonds))
nearlyTotalLength = len(workspace.initial) + len(workspace.target) - 2
bondDensity = numberOfBonds / nearlyTotalLength
if bondDensity > 1.0:
bondDensity = 1.0
cutoff = __getCutOff(bondDensity) * 10.0
bondDensity = min(bondDensity, 1.0)
weights = __getCutoffWeights(bondDensity)
cutoff = 10.0 * random.weighted_choice(range(1, 11), weights)
if cutoff >= temperature.actual_value:
if workspace.rule.buildTranslatedRule():
workspace.foundAnswer = True
@ -905,24 +910,19 @@ def bottom_up_correspondence_scout(ctx, codelet):
conceptMappings, flipTargetObject, codelet)
def chooseSlipnodeByConceptualDepth(slip_nodes, temperature):
if not slip_nodes:
return None
depths = [temperature.getAdjustedValue(n.conceptualDepth) for n in slip_nodes]
i = formulas.selectListPosition(depths)
return slip_nodes[i]
@codelet('important-object-correspondence-scout')
def important_object_correspondence_scout(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
slipnet = ctx.slipnet
temperature = ctx.temperature
workspace = ctx.workspace
objectFromInitial = chooseUnmodifiedObject('relativeImportance',
workspace.initial.objects)
descriptors = objectFromInitial.relevantDistinguishingDescriptors()
slipnode = chooseSlipnodeByConceptualDepth(descriptors, temperature)
# choose descriptor by conceptual depth
weights = [temperature.getAdjustedValue(n.conceptualDepth) for n in descriptors]
slipnode = random.weighted_choice(descriptors, weights)
assert slipnode
initialDescriptor = slipnode
for mapping in workspace.slippages():
@ -971,6 +971,7 @@ def important_object_correspondence_scout(ctx, codelet):
@codelet('correspondence-strength-tester')
def correspondence_strength_tester(ctx, codelet):
coderack = ctx.coderack
random = ctx.random
temperature = ctx.temperature
workspace = ctx.workspace
correspondence = codelet.arguments[0]
@ -984,7 +985,7 @@ def correspondence_strength_tester(ctx, codelet):
correspondence.updateStrength()
strength = correspondence.totalStrength
probability = temperature.getAdjustedProbability(strength / 100.0)
if formulas.coinFlip(probability):
if random.coinFlip(probability):
# activate some concepts
for mapping in correspondence.conceptMappings:
mapping.initialDescriptionType.buffer = 100.0

View File

@ -1,9 +1,7 @@
import math
import logging
import random
import codeletMethods
import formulas
from bond import Bond
from codelet import Codelet
from correspondence import Correspondence
@ -95,6 +93,7 @@ class Coderack(object):
return result
def howManyToPost(self, codeletName):
random = self.ctx.random
workspace = self.ctx.workspace
if codeletName == 'breaker' or 'description' in codeletName:
return 1
@ -117,9 +116,9 @@ class Coderack(object):
number = workspace.numberOfUnreplacedObjects()
if 'correspondence' in codeletName:
number = workspace.numberOfUncorrespondingObjects()
if number < formulas.blur(2.0):
if number < random.sqrtBlur(2.0):
return 1
if number < formulas.blur(4.0):
if number < random.sqrtBlur(4.0):
return 2
return 3
@ -131,6 +130,7 @@ class Coderack(object):
self.removeCodelet(oldCodelet)
def postTopDownCodelets(self):
random = self.ctx.random
slipnet = self.ctx.slipnet
for node in slipnet.slipnodes:
#logging.info('Trying slipnode: %s' % node.get_name())
@ -141,7 +141,7 @@ class Coderack(object):
probability = self.probabilityOfPosting(codeletName)
howMany = self.howManyToPost(codeletName)
for _ in xrange(howMany):
if not formulas.coinFlip(probability):
if not random.coinFlip(probability):
continue
urgency = getUrgencyBin(
node.activation * node.conceptualDepth / 100.0)
@ -164,6 +164,7 @@ class Coderack(object):
self.__postBottomUpCodelets('breaker')
def __postBottomUpCodelets(self, codeletName):
random = self.ctx.random
temperature = self.ctx.temperature
probability = self.probabilityOfPosting(codeletName)
howMany = self.howManyToPost(codeletName)
@ -173,7 +174,7 @@ class Coderack(object):
if temperature.value() < 25.0 and 'translator' in codeletName:
urgency = 5
for _ in xrange(howMany):
if formulas.coinFlip(probability):
if random.coinFlip(probability):
codelet = Codelet(codeletName, urgency, self.codeletsRun)
self.post(codelet)
@ -264,20 +265,13 @@ class Coderack(object):
def chooseOldCodelet(self):
# selects an old codelet to remove from the coderack
# more likely to select lower urgency codelets
if not len(self.codelets):
return None
urgencies = []
for codelet in self.codelets:
urgency = ((self.codeletsRun - codelet.birthdate) *
(7.5 - codelet.urgency))
urgencies += [urgency]
threshold = random.random() * sum(urgencies)
sumOfUrgencies = 0.0
for i in xrange(len(self.codelets)):
sumOfUrgencies += urgencies[i]
if sumOfUrgencies > threshold:
return self.codelets[i]
return self.codelets[0]
random = self.ctx.random
return random.weighted_choice(self.codelets, urgencies)
def postInitialCodelets(self):
workspace = self.ctx.workspace
@ -300,22 +294,12 @@ class Coderack(object):
self.run(codelet)
def chooseCodeletToRun(self):
random = self.ctx.random
temperature = self.ctx.temperature
assert self.codelets
scale = (100.0 - temperature.value() + 10.0) / 15.0
urgsum = sum(codelet.urgency ** scale for codelet in self.codelets)
threshold = random.random() * urgsum
chosen = self.codelets[0]
urgencySum = 0.0
for codelet in self.codelets:
urgencySum += codelet.urgency ** scale
if urgencySum > threshold:
chosen = codelet
break
chosen = random.weighted_choice(self.codelets, [codelet.urgency ** scale for codelet in self.codelets])
self.removeCodelet(chosen)
logging.info('chosen codelet\n\t%s, urgency = %s',
chosen.name, chosen.urgency)
return chosen
def run(self, codelet):

View File

@ -3,10 +3,11 @@ import logging
class Context(object):
def __init__(self):
self.temperature = None
self.coderack = None
self.workspace = None
self.random = None
self.slipnet = None
self.temperature = None
self.workspace = None
def mainLoop(self, lastUpdate):
currentTime = self.coderack.codeletsRun
@ -15,7 +16,7 @@ class Context(object):
if currentTime >= lastUpdate + 15:
self.workspace.updateEverything()
self.coderack.updateCodelets()
self.slipnet.update()
self.slipnet.update(self.random)
self.temperature.update(self.workspace.getUpdatedTemperature())
lastUpdate = currentTime
logging.debug('Number of codelets: %d', len(self.coderack.codelets))

View File

@ -1,16 +1,16 @@
import logging
from workspace import Workspace
from coderack import Coderack
from randomness import Randomness
from slipnet import Slipnet
from temperature import Temperature
from coderack import Coderack
from workspace import Workspace
from context import context
context.coderack = Coderack(context)
context.random = Randomness(42)
context.slipnet = Slipnet()
context.temperature = Temperature()
context.coderack = Coderack(context)
context.workspace = Workspace(context)

View File

@ -1,25 +1,6 @@
import math
import random
from conceptMapping import ConceptMapping
def selectListPosition(probabilities):
total = sum(probabilities)
#logging.info('total: %s' % total)
r = random.random()
stopPosition = total * r
#logging.info('stopPosition: %s' % stopPosition)
total = 0
i = 0
for probability in probabilities:
total += probability
if total > stopPosition:
return i
i += 1
return 0
def weightedAverage(values):
total = 0.0
totalWeights = 0.0
@ -31,27 +12,6 @@ def weightedAverage(values):
return total / totalWeights
def coinFlip(chance=0.5):
return random.random() < chance
def blur(value):
root = math.sqrt(value)
if coinFlip():
return value + root
return value - root
def chooseRelevantDescriptionByActivation(workspaceObject):
descriptions = workspaceObject.relevantDescriptions()
if not descriptions:
return None
activations = [description.descriptor.activation
for description in descriptions]
i = selectListPosition(activations)
return descriptions[i]
def __relevantCategory(objekt, slipnode):
return objekt.rightBond and objekt.rightBond.category == slipnode

View File

@ -1,5 +1,4 @@
import logging
import random
from workspaceObject import WorkspaceObject
import formulas
@ -73,9 +72,10 @@ class Group(WorkspaceObject):
def add_length_description_category(self):
#check whether or not to add length description category
random = self.ctx.random
slipnet = self.ctx.slipnet
probability = self.lengthDescriptionProbability()
if random.random() < probability:
if random.coinFlip(probability):
length = len(self.objectList)
if length < 6:
self.addDescription(slipnet.length,

View File

@ -1,11 +1,8 @@
"""Run the copycat program"""
import logging
import random
import sys
random.seed(42)
import copycat

41
copycat/randomness.py Normal file
View File

@ -0,0 +1,41 @@
import bisect
import math
import random
def accumulate(iterable):
total = 0
for v in iterable:
total += v
yield total
class Randomness(object):
def __init__(self, seed=None):
self.rng = random.Random(seed)
def coinFlip(self, p=0.5):
return self.rng.random() < p
def choice(self, seq):
return self.rng.choice(seq)
def weighted_choice(self, seq, weights):
if not seq:
# Many callers rely on this behavior.
return None
else:
cum_weights = list(accumulate(weights))
total = cum_weights[-1]
return seq[bisect.bisect_left(cum_weights, self.rng.random() * total)]
def weighted_greater_than(self, first, second):
total = first + second
if total == 0:
return False
return self.coinFlip(float(first) / total)
def sqrtBlur(self, value):
# This is exceedingly dumb, but it matches the Java code.
root = math.sqrt(value)
if self.coinFlip():
return value + root
return value - root

View File

@ -32,7 +32,7 @@ class Slipnet(object):
for node in self.initiallyClampedSlipnodes:
node.clampHigh()
def update(self):
def update(self, random):
logging.debug('slipnet.update()')
self.numberOfUpdates += 1
if self.numberOfUpdates == 50:
@ -44,7 +44,7 @@ class Slipnet(object):
node.spread_activation()
for node in self.slipnodes:
node.addBuffer()
node.jump()
node.jump(random)
node.buffer = 0.0
def isDistinguishingDescriptor(self, descriptor):

View File

@ -1,10 +1,5 @@
import math
import logging
import random
def full_activation():
return 100
def jump_threshold():
@ -65,11 +60,7 @@ class Slipnode(object):
def fully_active(self):
"""Whether this node has full activation"""
float_margin = 0.00001
return self.activation > full_activation() - float_margin
def activate_fully(self):
"""Make this node fully active"""
self.activation = full_activation()
return self.activation > 100.0 - float_margin
def bondDegreeOfAssociation(self):
linkLength = self.intrinsicLinkLength
@ -112,7 +103,8 @@ class Slipnode(object):
If no linked node is found, return None
"""
if relation == self.slipnet.identity:
slipnet = self.slipnet
if relation == slipnet.identity:
return self
destinations = [l.destination
for l in self.outgoingLinks if l.label == relation]
@ -125,9 +117,10 @@ class Slipnode(object):
If it does not exist return None
"""
slipnet = self.slipnet
result = None
if self == destination:
result = self.slipnet.identity
result = slipnet.identity
else:
for link in self.outgoingLinks:
if link.destination == destination:
@ -149,17 +142,14 @@ class Slipnode(object):
self.activation += self.buffer
self.activation = min(max(0, self.activation), 100)
def can_jump(self):
def jump(self, random):
if self.activation <= jump_threshold():
return False
return
if self.clamped:
return False
return
value = (self.activation / 100.0) ** 3
return random.random() < value
def jump(self):
if self.can_jump():
self.activate_fully()
if random.coinFlip(value):
self.activation = 100.0
def get_name(self):
if len(self.name) == 1:

View File

@ -1,34 +1,29 @@
import logging
import formulas
def __chooseObjectFromList(temperature, objects, attribute):
if not objects:
return None
def __chooseObjectFromList(ctx, objects, attribute):
random = ctx.random
temperature = ctx.temperature
weights = [
temperature.getAdjustedValue(
getattr(o, attribute)
)
for o in objects
]
i = formulas.selectListPosition(weights)
return objects[i]
return random.weighted_choice(objects, weights)
def chooseUnmodifiedObject(attribute, inObjects):
from context import context as ctx
temperature = ctx.temperature
workspace = ctx.workspace
objects = [o for o in inObjects if o.string != workspace.modified]
if not len(objects):
print 'no objects available in initial or target strings'
return __chooseObjectFromList(temperature, objects, attribute)
return __chooseObjectFromList(ctx, objects, attribute)
def chooseNeighbor(source):
from context import context as ctx
temperature = ctx.temperature
workspace = ctx.workspace
objects = []
for objekt in workspace.objects:
@ -38,7 +33,7 @@ def chooseNeighbor(source):
objects += [objekt]
elif source.leftIndex == objekt.rightIndex + 1:
objects += [objekt]
return __chooseObjectFromList(temperature, objects, "intraStringSalience")
return __chooseObjectFromList(ctx, objects, "intraStringSalience")
def chooseDirectedNeighbor(source, direction):
@ -53,7 +48,6 @@ def chooseDirectedNeighbor(source, direction):
def __chooseLeftNeighbor(source):
from context import context as ctx
temperature = ctx.temperature
workspace = ctx.workspace
objects = []
for o in workspace.objects:
@ -64,32 +58,29 @@ def __chooseLeftNeighbor(source):
else:
logging.info('%s is not on left of %s', o, source)
logging.info('Number of left objects: %s', len(objects))
return __chooseObjectFromList(temperature, objects, 'intraStringSalience')
return __chooseObjectFromList(ctx, objects, 'intraStringSalience')
def __chooseRightNeighbor(source):
from context import context as ctx
temperature = ctx.temperature
workspace = ctx.workspace
objects = [o for o in workspace.objects
if o.string == source.string
and o.leftIndex == source.rightIndex + 1]
return __chooseObjectFromList(temperature, objects, 'intraStringSalience')
return __chooseObjectFromList(ctx, objects, 'intraStringSalience')
def chooseBondFacet(source, destination):
from context import context as ctx
random = ctx.random
slipnet = ctx.slipnet
sourceFacets = [d.descriptionType for d in source.descriptions
if d.descriptionType in slipnet.bondFacets]
bondFacets = [d.descriptionType for d in destination.descriptions
if d.descriptionType in sourceFacets]
if not bondFacets:
return None
supports = [__supportForDescriptionType(f, source.string)
for f in bondFacets]
i = formulas.selectListPosition(supports)
return bondFacets[i]
return random.weighted_choice(bondFacets, supports)
def __supportForDescriptionType(descriptionType, string):