Adds automatic running, formula tests
This commit is contained in:
@ -4,7 +4,6 @@ from .slipnet import Slipnet
|
|||||||
from .temperature import Temperature
|
from .temperature import Temperature
|
||||||
from .workspace import Workspace
|
from .workspace import Workspace
|
||||||
|
|
||||||
|
|
||||||
class Reporter(object):
|
class Reporter(object):
|
||||||
"""Do-nothing base class for defining new reporter types"""
|
"""Do-nothing base class for defining new reporter types"""
|
||||||
def report_answer(self, answer):
|
def report_answer(self, answer):
|
||||||
@ -66,24 +65,36 @@ class Copycat(object):
|
|||||||
self.reporter.report_answer(answer)
|
self.reporter.report_answer(answer)
|
||||||
return answer
|
return answer
|
||||||
|
|
||||||
def run(self, initial, modified, target, iterations):
|
def run(self, initial, modified, target, iterations, testAdjFormulas=False):
|
||||||
self.workspace.resetWithStrings(initial, modified, target)
|
self.workspace.resetWithStrings(initial, modified, target)
|
||||||
answers = {}
|
if testAdjFormulas:
|
||||||
for i in range(iterations):
|
formulas = self.temperature.adj_formulas()
|
||||||
answer = self.runTrial()
|
else:
|
||||||
d = answers.setdefault(answer['answer'], {
|
formulas = ['original']
|
||||||
'count': 0,
|
|
||||||
'sumtemp': 0, # TODO: use entropy
|
|
||||||
'sumtime': 0
|
|
||||||
})
|
|
||||||
d['count'] += 1
|
|
||||||
d['sumtemp'] += answer['temp'] # TODO: use entropy
|
|
||||||
d['sumtime'] += answer['time']
|
|
||||||
|
|
||||||
for answer, d in answers.items():
|
formulaList = []
|
||||||
d['avgtemp'] = d.pop('sumtemp') / d['count']
|
for formula in formulas:
|
||||||
d['avgtime'] = d.pop('sumtime') / d['count']
|
self.temperature.useAdj(formula)
|
||||||
return answers
|
answers = {}
|
||||||
|
for i in range(iterations):
|
||||||
|
answer = self.runTrial()
|
||||||
|
d = answers.setdefault(answer['answer'], {
|
||||||
|
'count': 0,
|
||||||
|
'sumtemp': 0, # TODO: use entropy
|
||||||
|
'sumtime': 0
|
||||||
|
})
|
||||||
|
d['count'] += 1
|
||||||
|
d['sumtemp'] += answer['temp'] # TODO: use entropy
|
||||||
|
d['sumtime'] += answer['time']
|
||||||
|
|
||||||
|
for answer, d in answers.items():
|
||||||
|
d['avgtemp'] = d.pop('sumtemp') / d['count']
|
||||||
|
d['avgtime'] = d.pop('sumtime') / d['count']
|
||||||
|
formulaList.append(answers)
|
||||||
|
if not testAdjFormulas:
|
||||||
|
return formulaList[0]
|
||||||
|
else:
|
||||||
|
return formulaList
|
||||||
|
|
||||||
def run_forever(self, initial, modified, target):
|
def run_forever(self, initial, modified, target):
|
||||||
self.workspace.resetWithStrings(initial, modified, target)
|
self.workspace.resetWithStrings(initial, modified, target)
|
||||||
|
|||||||
@ -1,8 +1,44 @@
|
|||||||
import math
|
import math
|
||||||
|
|
||||||
|
# Alternate formulas for getAdjustedProbability
|
||||||
|
|
||||||
|
def _original(temp, prob):
|
||||||
|
if prob == 0 or prob == 0.5 or temp == 0:
|
||||||
|
return prob
|
||||||
|
if prob < 0.5:
|
||||||
|
return 1.0 - _original(temp, 1.0 - prob)
|
||||||
|
coldness = 100.0 - temp
|
||||||
|
a = math.sqrt(coldness)
|
||||||
|
c = (10 - a) / 100
|
||||||
|
f = (c + 1) * prob
|
||||||
|
return max(f, 0.5)
|
||||||
|
|
||||||
|
def _entropy(temp, prob):
|
||||||
|
if prob == 0 or prob == 0.5 or temp == 0:
|
||||||
|
return prob
|
||||||
|
if prob < 0.5:
|
||||||
|
return 1.0 - _original(temp, 1.0 - prob)
|
||||||
|
coldness = 100.0 - temp
|
||||||
|
a = math.sqrt(coldness)
|
||||||
|
c = (10 - a) / 100
|
||||||
|
f = (c + 1) * prob
|
||||||
|
return -f * math.log2(f)
|
||||||
|
|
||||||
|
def _inverse_prob(temp, prob):
|
||||||
|
# Temperature, potentially clamped
|
||||||
|
iprob = 1 - prob
|
||||||
|
return (temp / 100) * iprob + ((100 - temp) / 100) * prob
|
||||||
|
|
||||||
|
|
||||||
class Temperature(object):
|
class Temperature(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
|
self.adjustmentType = 'original'
|
||||||
|
self._adjustmentFormulas = {
|
||||||
|
'original' : _original,
|
||||||
|
'entropy' : _entropy,
|
||||||
|
'inverse' : _inverse_prob
|
||||||
|
}
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.actual_value = 100.0
|
self.actual_value = 100.0
|
||||||
@ -32,7 +68,19 @@ class Temperature(object):
|
|||||||
def getAdjustedValue(self, value):
|
def getAdjustedValue(self, value):
|
||||||
return value ** (((100.0 - self.value()) / 30.0) + 0.5)
|
return value ** (((100.0 - self.value()) / 30.0) + 0.5)
|
||||||
|
|
||||||
"""
|
def getAdjustedProbability(self, value):
|
||||||
|
temp = self.value()
|
||||||
|
prob = value
|
||||||
|
return self._adjustmentFormulas[self.adjustmentType](temp, prob)
|
||||||
|
|
||||||
|
def useAdj(self, adj):
|
||||||
|
print('Changing to adjustment formula {}'.format(adj))
|
||||||
|
self.adjustmentType = adj
|
||||||
|
|
||||||
|
def adj_formulas(self):
|
||||||
|
return self._adjustmentFormulas.keys()
|
||||||
|
|
||||||
|
'''
|
||||||
def getAdjustedProbability(self, value):
|
def getAdjustedProbability(self, value):
|
||||||
if value == 0 or value == 0.5 or self.value() == 0:
|
if value == 0 or value == 0.5 or self.value() == 0:
|
||||||
return value
|
return value
|
||||||
@ -43,9 +91,20 @@ class Temperature(object):
|
|||||||
c = (10 - a) / 100
|
c = (10 - a) / 100
|
||||||
f = (c + 1) * value
|
f = (c + 1) * value
|
||||||
return max(f, 0.5)
|
return max(f, 0.5)
|
||||||
"""
|
|
||||||
|
|
||||||
def getAdjustedProbability(self, value):
|
def getAdjustedProbability(self, value):
|
||||||
|
if value == 0 or value == 0.5 or self.value() == 0:
|
||||||
|
return value
|
||||||
|
if value < 0.5:
|
||||||
|
return 1.0 - self.getAdjustedProbability(1.0 - value)
|
||||||
|
coldness = 100.0 - self.value()
|
||||||
|
a = math.sqrt(coldness)
|
||||||
|
c = (10 - a) / 100
|
||||||
|
f = (c + 1) * value
|
||||||
|
# return max(f, 0.5)
|
||||||
|
# return max(f, 0.0)
|
||||||
|
# return (0 + (-f * math.log2(f)))
|
||||||
|
return -f * math.log2(f)
|
||||||
# TODO: use entropy
|
# TODO: use entropy
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -291,9 +350,13 @@ class Temperature(object):
|
|||||||
# This function does precisely what I think the original lisp comment describes, but provides crappy results
|
# This function does precisely what I think the original lisp comment describes, but provides crappy results
|
||||||
# return (temp / 200) * iprob + ((200 - temp) / 200) * prob
|
# return (temp / 200) * iprob + ((200 - temp) / 200) * prob
|
||||||
# However, this version preforms much better:
|
# However, this version preforms much better:
|
||||||
|
# Essentially, it weights probabilities towards their inverses when temperature is higher, and leaves them unaffected when it is lower.
|
||||||
# Some statistical analysis is needed of course
|
# Some statistical analysis is needed of course
|
||||||
return (temp / 100) * iprob + ((100 - temp) / 100) * prob
|
return (temp / 100) * iprob + ((100 - temp) / 100) * prob
|
||||||
'''
|
|
||||||
|
# This will give only xyd answers:
|
||||||
|
#return 1 - (temp / 100) * iprob + ((100 - temp) / 100) * prob
|
||||||
|
"""
|
||||||
lucas@infinity:~/projects/personal/copycat$ ./main.py abc abd xyz --iterations 10 --plot
|
lucas@infinity:~/projects/personal/copycat$ ./main.py abc abd xyz --iterations 10 --plot
|
||||||
Answered wyz (time 3865, final temperature 13.9)
|
Answered wyz (time 3865, final temperature 13.9)
|
||||||
Answered wyz (time 8462, final temperature 10.8)
|
Answered wyz (time 8462, final temperature 10.8)
|
||||||
@ -324,7 +387,7 @@ class Temperature(object):
|
|||||||
Answered ijjkkl (time 1064, final temperature 50.6)
|
Answered ijjkkl (time 1064, final temperature 50.6)
|
||||||
ijjlll: 3 (avg time 3051.0, avg temp 16.1)
|
ijjlll: 3 (avg time 3051.0, avg temp 16.1)
|
||||||
ijjkkl: 7 (avg time 1540.4, avg temp 42.6)
|
ijjkkl: 7 (avg time 1540.4, avg temp 42.6)
|
||||||
'''
|
"""
|
||||||
# unparameterized version
|
# unparameterized version
|
||||||
#curvedProb = (temp / 100) * iprob + (cold / 100) * prob
|
#curvedProb = (temp / 100) * iprob + (cold / 100) * prob
|
||||||
|
|
||||||
@ -340,7 +403,7 @@ class Temperature(object):
|
|||||||
# beta = 1.0
|
# beta = 1.0
|
||||||
# return ((alpha + temp / 100) * iprob + (beta + cold / 100) * prob) / (alpha + beta)
|
# return ((alpha + temp / 100) * iprob + (beta + cold / 100) * prob) / (alpha + beta)
|
||||||
|
|
||||||
'''
|
"""
|
||||||
# A scaling factor (between 0 and infinity), based on temperature (i.e. 100/coldness)
|
# A scaling factor (between 0 and infinity), based on temperature (i.e. 100/coldness)
|
||||||
if temp == 100: # Avoid dividing by zero
|
if temp == 100: # Avoid dividing by zero
|
||||||
factor = float('inf')
|
factor = float('inf')
|
||||||
|
|||||||
33
multi-run.py
Executable file
33
multi-run.py
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse, logging
|
||||||
|
from copycat import Copycat, Reporter, plot_answers, save_answers
|
||||||
|
|
||||||
|
class SimpleReporter(Reporter):
|
||||||
|
"""Reports results from a single run."""
|
||||||
|
def report_answer(self, answer):
|
||||||
|
"""Self-explanatory code."""
|
||||||
|
print('Answered %s (time %d, final temperature %.1f)' % (
|
||||||
|
answer['answer'], answer['time'], answer['temp'],
|
||||||
|
))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--iterations', type=int, default=1, help='Run the given case this many times.')
|
||||||
|
options = parser.parse_args()
|
||||||
|
|
||||||
|
copycat = Copycat(reporter=SimpleReporter())
|
||||||
|
|
||||||
|
with open('input/reduced_problems.csv', 'r') as infile:
|
||||||
|
for line in infile:
|
||||||
|
line = line.replace('\n', '')
|
||||||
|
a, b, c = line.split(',')
|
||||||
|
answerList = copycat.run(a, b, c, options.iterations, True)
|
||||||
|
for answers in answerList:
|
||||||
|
for answer, d in sorted(iter(answers.items()), key=lambda kv: kv[1]['avgtemp']):
|
||||||
|
print('%s: %d (avg time %.1f, avg temp %.1f)' % (answer, d['count'], d['avgtime'], d['avgtemp']))
|
||||||
|
|
||||||
|
#filename = 'output/{}-{}-{}.csv'.format(a, b, c)
|
||||||
|
#save_answers(answers, filename)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user