Adds automatic running, formula tests
This commit is contained in:
@ -4,7 +4,6 @@ from .slipnet import Slipnet
|
||||
from .temperature import Temperature
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class Reporter(object):
|
||||
"""Do-nothing base class for defining new reporter types"""
|
||||
def report_answer(self, answer):
|
||||
@ -66,24 +65,36 @@ class Copycat(object):
|
||||
self.reporter.report_answer(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)
|
||||
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']
|
||||
if testAdjFormulas:
|
||||
formulas = self.temperature.adj_formulas()
|
||||
else:
|
||||
formulas = ['original']
|
||||
|
||||
for answer, d in answers.items():
|
||||
d['avgtemp'] = d.pop('sumtemp') / d['count']
|
||||
d['avgtime'] = d.pop('sumtime') / d['count']
|
||||
return answers
|
||||
formulaList = []
|
||||
for formula in formulas:
|
||||
self.temperature.useAdj(formula)
|
||||
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):
|
||||
self.workspace.resetWithStrings(initial, modified, target)
|
||||
|
||||
@ -1,8 +1,44 @@
|
||||
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):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
self.adjustmentType = 'original'
|
||||
self._adjustmentFormulas = {
|
||||
'original' : _original,
|
||||
'entropy' : _entropy,
|
||||
'inverse' : _inverse_prob
|
||||
}
|
||||
|
||||
def reset(self):
|
||||
self.actual_value = 100.0
|
||||
@ -32,7 +68,19 @@ class Temperature(object):
|
||||
def getAdjustedValue(self, value):
|
||||
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):
|
||||
if value == 0 or value == 0.5 or self.value() == 0:
|
||||
return value
|
||||
@ -43,9 +91,20 @@ class Temperature(object):
|
||||
c = (10 - a) / 100
|
||||
f = (c + 1) * value
|
||||
return max(f, 0.5)
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
"""
|
||||
@ -291,9 +350,13 @@ class Temperature(object):
|
||||
# This function does precisely what I think the original lisp comment describes, but provides crappy results
|
||||
# return (temp / 200) * iprob + ((200 - temp) / 200) * prob
|
||||
# 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
|
||||
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
|
||||
Answered wyz (time 3865, final temperature 13.9)
|
||||
Answered wyz (time 8462, final temperature 10.8)
|
||||
@ -324,7 +387,7 @@ class Temperature(object):
|
||||
Answered ijjkkl (time 1064, final temperature 50.6)
|
||||
ijjlll: 3 (avg time 3051.0, avg temp 16.1)
|
||||
ijjkkl: 7 (avg time 1540.4, avg temp 42.6)
|
||||
'''
|
||||
"""
|
||||
# unparameterized version
|
||||
#curvedProb = (temp / 100) * iprob + (cold / 100) * prob
|
||||
|
||||
@ -340,7 +403,7 @@ class Temperature(object):
|
||||
# beta = 1.0
|
||||
# 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)
|
||||
if temp == 100: # Avoid dividing by zero
|
||||
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