Major overhaul of temperature logic. Behavioral change.
I think the reason the temperature logic was so confused in the old code is because the Java code has a class `Temperature` that is used for graphical display *and* two variables in `formulas` that are used for most of the actual math. But somewhere along the line, some of the code in `formulas.java` started reading from `Temperature.value` as well. So the Python code was just faithfully copying that confusion. The actual abstraction here is a very simple "temperature" object with a stored value. It can be "clamped" to 100.0 for a given period. The only complication is that one of the codelets (the rule-transformer codelet) wants to get access to the "actual value" of the temperature even when it is clamped. The Python rule-transformer codelet also had a bug: it was accidentally setting `temperature.value` on the `temperature` module instead of on the `temperature.temperature` object! This turned some of its behavior into a no-op, for whatever that's worth. Lastly, the calculation of `finalTemperature` in the main program can now report 100.0 if the answer is found while the temperature is clamped. I don't fully understand why this didn't happen in the old code. I've hacked around it with `temperature.last_unclamped_value` for now, but I should TODO FIXME.
This commit is contained in:
@ -3,7 +3,7 @@ import logging
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from slipnet import slipnet
|
from slipnet import slipnet
|
||||||
import temperature
|
from temperature import temperature
|
||||||
import formulas
|
import formulas
|
||||||
from workspaceFormulas import chooseDirectedNeighbor
|
from workspaceFormulas import chooseDirectedNeighbor
|
||||||
from workspaceFormulas import chooseNeighbor
|
from workspaceFormulas import chooseNeighbor
|
||||||
@ -130,7 +130,7 @@ def __slippability(conceptMappings):
|
|||||||
|
|
||||||
@codelet('breaker')
|
@codelet('breaker')
|
||||||
def breaker(coderack, codelet):
|
def breaker(coderack, codelet):
|
||||||
probabilityOfFizzle = (100.0 - formulas.Temperature) / 100.0
|
probabilityOfFizzle = (100.0 - temperature.value()) / 100.0
|
||||||
if formulas.coinFlip(probabilityOfFizzle):
|
if formulas.coinFlip(probabilityOfFizzle):
|
||||||
return
|
return
|
||||||
# choose a structure at random
|
# choose a structure at random
|
||||||
@ -804,13 +804,11 @@ def rule_translator(coderack, codelet):
|
|||||||
if bondDensity > 1.0:
|
if bondDensity > 1.0:
|
||||||
bondDensity = 1.0
|
bondDensity = 1.0
|
||||||
cutoff = __getCutOff(bondDensity) * 10.0
|
cutoff = __getCutOff(bondDensity) * 10.0
|
||||||
assert cutoff >= formulas.actualTemperature
|
if cutoff >= temperature.actual_value:
|
||||||
if workspace.rule.buildTranslatedRule():
|
if workspace.rule.buildTranslatedRule():
|
||||||
workspace.foundAnswer = True
|
workspace.foundAnswer = True
|
||||||
else:
|
else:
|
||||||
temperature.clampTime = coderack.codeletsRun + 100
|
temperature.clampUntil(coderack.codeletsRun + 100)
|
||||||
temperature.clamped = True
|
|
||||||
formulas.Temperature = 100.0
|
|
||||||
|
|
||||||
|
|
||||||
@codelet('bottom-up-correspondence-scout')
|
@codelet('bottom-up-correspondence-scout')
|
||||||
|
|||||||
@ -23,7 +23,7 @@ def probabilityOfPosting(workspace, codeletName):
|
|||||||
if codeletName == 'breaker':
|
if codeletName == 'breaker':
|
||||||
return 1.0
|
return 1.0
|
||||||
if 'description' in codeletName:
|
if 'description' in codeletName:
|
||||||
result = (formulas.Temperature / 100.0) ** 2
|
result = (temperature.value() / 100.0) ** 2
|
||||||
else:
|
else:
|
||||||
result = workspace.intraStringUnhappiness / 100.0
|
result = workspace.intraStringUnhappiness / 100.0
|
||||||
if 'correspondence' in codeletName:
|
if 'correspondence' in codeletName:
|
||||||
@ -165,7 +165,7 @@ class Coderack(object):
|
|||||||
urgency = 3
|
urgency = 3
|
||||||
if codeletName == 'breaker':
|
if codeletName == 'breaker':
|
||||||
urgency = 1
|
urgency = 1
|
||||||
if formulas.Temperature < 25.0 and 'translator' in codeletName:
|
if temperature.value() < 25.0 and 'translator' in codeletName:
|
||||||
urgency = 5
|
urgency = 5
|
||||||
for _ in xrange(howMany):
|
for _ in xrange(howMany):
|
||||||
if formulas.coinFlip(probability):
|
if formulas.coinFlip(probability):
|
||||||
@ -303,7 +303,7 @@ class Coderack(object):
|
|||||||
|
|
||||||
def chooseCodeletToRun(self):
|
def chooseCodeletToRun(self):
|
||||||
assert self.codelets
|
assert self.codelets
|
||||||
scale = (100.0 - formulas.Temperature + 10.0) / 15.0
|
scale = (100.0 - temperature.value() + 10.0) / 15.0
|
||||||
urgsum = sum(codelet.urgency ** scale for codelet in self.codelets)
|
urgsum = sum(codelet.urgency ** scale for codelet in self.codelets)
|
||||||
threshold = random.random() * urgsum
|
threshold = random.random() * urgsum
|
||||||
chosen = self.codelets[0]
|
chosen = self.codelets[0]
|
||||||
|
|||||||
@ -17,7 +17,7 @@ def mainLoop(lastUpdate):
|
|||||||
workspace.updateEverything()
|
workspace.updateEverything()
|
||||||
coderack.updateCodelets()
|
coderack.updateCodelets()
|
||||||
slipnet.update()
|
slipnet.update()
|
||||||
workspace.updateTemperature()
|
temperature.update(workspace.getUpdatedTemperature())
|
||||||
lastUpdate = currentTime
|
lastUpdate = currentTime
|
||||||
logging.debug('Number of codelets: %d', len(coderack.codelets))
|
logging.debug('Number of codelets: %d', len(coderack.codelets))
|
||||||
coderack.chooseAndRunCodelet()
|
coderack.chooseAndRunCodelet()
|
||||||
@ -36,7 +36,7 @@ def runTrial(answers):
|
|||||||
answer = workspace.rule.finalAnswer
|
answer = workspace.rule.finalAnswer
|
||||||
else:
|
else:
|
||||||
answer = None
|
answer = None
|
||||||
finalTemperature = temperature.value
|
finalTemperature = temperature.last_unclamped_value
|
||||||
finalTime = coderack.codeletsRun
|
finalTime = coderack.codeletsRun
|
||||||
print 'Answered %s (time %d, final temperature %.1f)' % (answer, finalTime, finalTemperature)
|
print 'Answered %s (time %d, final temperature %.1f)' % (answer, finalTime, finalTemperature)
|
||||||
answers[answer] = answers.get(answer, {'count': 0, 'tempsum': 0, 'timesum': 0})
|
answers[answer] = answers.get(answer, {'count': 0, 'tempsum': 0, 'timesum': 0})
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import random
|
|||||||
|
|
||||||
from temperature import temperature
|
from temperature import temperature
|
||||||
|
|
||||||
actualTemperature = Temperature = 100.0
|
|
||||||
|
|
||||||
|
|
||||||
def selectListPosition(probabilities):
|
def selectListPosition(probabilities):
|
||||||
total = sum(probabilities)
|
total = sum(probabilities)
|
||||||
@ -35,23 +33,18 @@ def weightedAverage(values):
|
|||||||
|
|
||||||
|
|
||||||
def temperatureAdjustedValue(value):
|
def temperatureAdjustedValue(value):
|
||||||
#logging.info('Temperature: %s' % Temperature)
|
return value ** (((100.0 - temperature.value()) / 30.0) + 0.5)
|
||||||
#logging.info('actualTemperature: %s' % actualTemperature)
|
|
||||||
return value ** (((100.0 - Temperature) / 30.0) + 0.5)
|
|
||||||
|
|
||||||
|
|
||||||
def temperatureAdjustedProbability(value):
|
def temperatureAdjustedProbability(value):
|
||||||
if not value or value == 0.5 or not temperature.value:
|
if value == 0 or value == 0.5 or temperature.value() == 0:
|
||||||
return value
|
return value
|
||||||
if value < 0.5:
|
if value < 0.5:
|
||||||
return 1.0 - temperatureAdjustedProbability(1.0 - value)
|
return 1.0 - temperatureAdjustedProbability(1.0 - value)
|
||||||
coldness = 100.0 - temperature.value
|
coldness = 100.0 - temperature.value()
|
||||||
a = math.sqrt(coldness)
|
a = math.sqrt(coldness)
|
||||||
b = 10.0 - a
|
c = (10 - a) / 100
|
||||||
c = b / 100
|
f = (c + 1) * value
|
||||||
d = c * (1.0 - (1.0 - value)) # as said the java
|
|
||||||
e = (1.0 - value) + d
|
|
||||||
f = 1.0 - e
|
|
||||||
return max(f, 0.5)
|
return max(f, 0.5)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,29 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
class Temperature(object):
|
class Temperature(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.value = 100.0
|
self.actual_value = 100.0
|
||||||
|
self.last_unclamped_value = 100.0
|
||||||
self.clamped = True
|
self.clamped = True
|
||||||
self.clampTime = 30
|
self.clampTime = 30
|
||||||
|
|
||||||
def update(self, value):
|
def update(self, value):
|
||||||
self.value = value
|
self.last_unclamped_value = value
|
||||||
|
if self.clamped:
|
||||||
|
self.actual_value = 100.0
|
||||||
|
else:
|
||||||
|
self.actual_value = value
|
||||||
|
|
||||||
|
def clampUntil(self, when):
|
||||||
|
self.clamped = True
|
||||||
|
self.clampTime = when
|
||||||
|
# but do not modify self.actual_value until someone calls update()
|
||||||
|
|
||||||
def tryUnclamp(self, currentTime):
|
def tryUnclamp(self, currentTime):
|
||||||
if self.clamped and currentTime >= self.clampTime:
|
if self.clamped and currentTime >= self.clampTime:
|
||||||
logging.info('unclamp temperature at %d', currentTime)
|
|
||||||
self.clamped = False
|
self.clamped = False
|
||||||
|
|
||||||
|
def value(self):
|
||||||
|
return 100.0 if self.clamped else self.actual_value
|
||||||
|
|
||||||
|
|
||||||
temperature = Temperature()
|
temperature = Temperature()
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import formulas
|
import formulas
|
||||||
from temperature import temperature
|
|
||||||
from workspaceString import WorkspaceString
|
from workspaceString import WorkspaceString
|
||||||
|
|
||||||
|
|
||||||
@ -85,19 +84,14 @@ class Workspace(object):
|
|||||||
self.initial.updateIntraStringUnhappiness()
|
self.initial.updateIntraStringUnhappiness()
|
||||||
self.target.updateIntraStringUnhappiness()
|
self.target.updateIntraStringUnhappiness()
|
||||||
|
|
||||||
def updateTemperature(self):
|
def getUpdatedTemperature(self):
|
||||||
self.assessTemperature()
|
self.assessTemperature()
|
||||||
ruleWeakness = 100.0
|
ruleWeakness = 100.0
|
||||||
if self.rule:
|
if self.rule:
|
||||||
self.rule.updateStrength()
|
self.rule.updateStrength()
|
||||||
ruleWeakness = 100.0 - self.rule.totalStrength
|
ruleWeakness = 100.0 - self.rule.totalStrength
|
||||||
values = ((self.totalUnhappiness, 0.8), (ruleWeakness, 0.2))
|
values = ((self.totalUnhappiness, 0.8), (ruleWeakness, 0.2))
|
||||||
above_actual_temperature = formulas.actualTemperature + 0.001
|
return formulas.weightedAverage(values)
|
||||||
formulas.actualTemperature = formulas.weightedAverage(values)
|
|
||||||
if temperature.clamped:
|
|
||||||
formulas.actualTemperature = 100.0
|
|
||||||
formulas.Temperature = formulas.actualTemperature
|
|
||||||
temperature.update(formulas.Temperature)
|
|
||||||
|
|
||||||
def numberOfUnrelatedObjects(self):
|
def numberOfUnrelatedObjects(self):
|
||||||
"""A list of all objects in the workspace with >= 1 open bond slots"""
|
"""A list of all objects in the workspace with >= 1 open bond slots"""
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from workspace import workspace
|
from workspace import workspace
|
||||||
from temperature import temperature
|
|
||||||
from slipnet import slipnet
|
from slipnet import slipnet
|
||||||
import formulas
|
import formulas
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user