From ef0e177badfa773fb1cd69e4dc3862775a25fd69 Mon Sep 17 00:00:00 2001 From: LSaldyt Date: Wed, 11 Oct 2017 19:50:33 -0600 Subject: [PATCH 1/5] WIP --- copycat/temperature.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/copycat/temperature.py b/copycat/temperature.py index 2a72e64..d97aef0 100644 --- a/copycat/temperature.py +++ b/copycat/temperature.py @@ -24,9 +24,14 @@ def _entropy(temp, prob): f = (c + 1) * prob return -f * math.log2(f) -def _inverse_prob(temp, prob): +def _weighted_inverse(temp, prob): + alpha = 10 + beta = 1 + iprob = 1 - prob - return (temp / 100) * iprob + ((100 - temp) / 100) * prob + inverse_weighted = (temp / 100) * iprob + ((100 - temp) / 100) * prob + + return (alpha * inverse_weighted + beta * prob) / (alpha + beta) class Temperature(object): def __init__(self): @@ -35,7 +40,7 @@ class Temperature(object): self._adjustmentFormulas = { 'original' : _original, 'entropy' : _entropy, - 'inverse' : _inverse_prob} + 'inverse' : _weighted_inverse} def reset(self): self.actual_value = 100.0 From 0ba421029cd47462c3c1d7a7bb489063cabedf9c Mon Sep 17 00:00:00 2001 From: LSaldyt Date: Wed, 11 Oct 2017 22:12:53 -0600 Subject: [PATCH 2/5] Adds additional formulas, weights, and tests --- copycat/copycat.py | 6 +++++- copycat/temperature.py | 35 +++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/copycat/copycat.py b/copycat/copycat.py index 2adff4a..33e408b 100644 --- a/copycat/copycat.py +++ b/copycat/copycat.py @@ -70,7 +70,11 @@ class Copycat(object): #self.temperature.useAdj('original') #self.temperature.useAdj('entropy') - self.temperature.useAdj('inverse') # 100 weight + #self.temperature.useAdj('inverse') # 100 weight + #self.temperature.useAdj('fifty_converge') + #self.temperature.useAdj('soft') + self.temperature.useAdj('weighted_soft') + answers = {} for i in range(iterations): answer = self.runTrial() diff --git a/copycat/temperature.py b/copycat/temperature.py index d97aef0..e47c20f 100644 --- a/copycat/temperature.py +++ b/copycat/temperature.py @@ -25,22 +25,41 @@ def _entropy(temp, prob): return -f * math.log2(f) def _weighted_inverse(temp, prob): - alpha = 10 - beta = 1 - iprob = 1 - prob - inverse_weighted = (temp / 100) * iprob + ((100 - temp) / 100) * prob + weight = 100 + inverse_weighted = (temp / weight) * iprob + ((weight - temp) / weight) * prob + return inverse_weighted - return (alpha * inverse_weighted + beta * prob) / (alpha + beta) +def _fifty_converge(temp, prob): # Uses .5 instead of 1-prob + weight = 100 + curved = (temp / weight) * .5 + ((weight - temp) / weight) * prob + return curved + +def _soft_curve(temp, prob): # Curves to the average of the (1-p) and .5 + iprob = 1 - prob + weight = 100 + curved = min(1, (temp / weight) * ((1.5 - prob) / 2) + ((weight - temp) / weight) * prob) + return curved + +def _weighted_soft_curve(temp, prob): # Curves to the weighted average of the (1-p) and .5 + weight = 100 # Don't change me in this context + gamma = .5 # convergance value + alpha = 1 # gamma weight + beta = 3 # iprob weight + curved = min(1, (temp / weight) * ((alpha * gamma + beta * (1 - prob)) / (alpha + beta)) + ((weight - temp) / weight) * prob) + return curved class Temperature(object): def __init__(self): self.reset() self.adjustmentType = 'inverse' self._adjustmentFormulas = { - 'original' : _original, - 'entropy' : _entropy, - 'inverse' : _weighted_inverse} + 'original' : _original, + 'entropy' : _entropy, + 'inverse' : _weighted_inverse, + 'fifty_converge' : _fifty_converge, + 'soft' : _soft_curve, + 'weighted_soft' : _weighted_soft_curve} def reset(self): self.actual_value = 100.0 From 6985dedb18945f3af6df2c4f979a6745493a3121 Mon Sep 17 00:00:00 2001 From: LSaldyt Date: Sun, 15 Oct 2017 14:38:48 -0600 Subject: [PATCH 3/5] Adds additional adjustment formulas --- copycat/copycat.py | 6 ++++-- copycat/temperature.py | 33 +++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/copycat/copycat.py b/copycat/copycat.py index 33e408b..1f16cd9 100644 --- a/copycat/copycat.py +++ b/copycat/copycat.py @@ -68,12 +68,14 @@ class Copycat(object): def run(self, initial, modified, target, iterations): self.workspace.resetWithStrings(initial, modified, target) - #self.temperature.useAdj('original') + self.temperature.useAdj('original') #self.temperature.useAdj('entropy') #self.temperature.useAdj('inverse') # 100 weight #self.temperature.useAdj('fifty_converge') #self.temperature.useAdj('soft') - self.temperature.useAdj('weighted_soft') + #self.temperature.useAdj('weighted_soft') + #self.temperature.useAdj('alt_fifty') + #self.temperature.useAdj('average_alt') answers = {} for i in range(iterations): diff --git a/copycat/temperature.py b/copycat/temperature.py index e47c20f..20aca17 100644 --- a/copycat/temperature.py +++ b/copycat/temperature.py @@ -24,31 +24,38 @@ def _entropy(temp, prob): f = (c + 1) * prob return -f * math.log2(f) +def _weighted(temp, prob, s, u): + weighted = (temp / 100) * s + ((100 - temp) / 100) * u + return weighted + def _weighted_inverse(temp, prob): iprob = 1 - prob - weight = 100 - inverse_weighted = (temp / weight) * iprob + ((weight - temp) / weight) * prob - return inverse_weighted + return _weighted(temp, prob, iprob, prob) def _fifty_converge(temp, prob): # Uses .5 instead of 1-prob - weight = 100 - curved = (temp / weight) * .5 + ((weight - temp) / weight) * prob - return curved + return _weighted(temp, prob, .5, prob) def _soft_curve(temp, prob): # Curves to the average of the (1-p) and .5 - iprob = 1 - prob - weight = 100 - curved = min(1, (temp / weight) * ((1.5 - prob) / 2) + ((weight - temp) / weight) * prob) - return curved + return min(1, _weighted(temp, prob, (1.5-prob)/2, prob)) def _weighted_soft_curve(temp, prob): # Curves to the weighted average of the (1-p) and .5 - weight = 100 # Don't change me in this context + weight = 100 gamma = .5 # convergance value alpha = 1 # gamma weight beta = 3 # iprob weight curved = min(1, (temp / weight) * ((alpha * gamma + beta * (1 - prob)) / (alpha + beta)) + ((weight - temp) / weight) * prob) return curved +def _alt_fifty(temp, prob): + s = .5 + u = prob ** 2 if prob < .5 else math.sqrt(prob) + return _weighted(temp, prob, s, u) + +def _averaged_alt(temp, prob): + s = (1.5 - prob)/2 + u = prob ** 2 if prob < .5 else math.sqrt(prob) + return _weighted(temp, prob, s, u) + class Temperature(object): def __init__(self): self.reset() @@ -59,7 +66,9 @@ class Temperature(object): 'inverse' : _weighted_inverse, 'fifty_converge' : _fifty_converge, 'soft' : _soft_curve, - 'weighted_soft' : _weighted_soft_curve} + 'weighted_soft' : _weighted_soft_curve, + 'alt_fifty' : _alt_fifty, + 'average_alt' : _averaged_alt} def reset(self): self.actual_value = 100.0 From 765323c3cd539ab1ec7aacdcbd4d7279445273af Mon Sep 17 00:00:00 2001 From: lsaldyt Date: Mon, 16 Oct 2017 13:21:19 -0700 Subject: [PATCH 4/5] Updates adjustment formula to a satisfactory formula Out of all of the formulas I've tried, I believe this formula to be a more elegant alternative to Mitchell's formula. However, like Mitchell's original formula, it still provides weird answers in some cases, but I believe these to source from elsewhere, not from the adjustment formula. For more information, please see: https://docs.google.com/spreadsheets/d/1JT2yCBUAsFzMcbKsQUcH1DhcBbuWDKTgPvUwD9EqyTY/edit?usp=sharing wq --- copycat/copycat.py | 3 ++- copycat/temperature.py | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/copycat/copycat.py b/copycat/copycat.py index 1f16cd9..e66a738 100644 --- a/copycat/copycat.py +++ b/copycat/copycat.py @@ -68,7 +68,7 @@ class Copycat(object): def run(self, initial, modified, target, iterations): self.workspace.resetWithStrings(initial, modified, target) - self.temperature.useAdj('original') + #self.temperature.useAdj('original') #self.temperature.useAdj('entropy') #self.temperature.useAdj('inverse') # 100 weight #self.temperature.useAdj('fifty_converge') @@ -76,6 +76,7 @@ class Copycat(object): #self.temperature.useAdj('weighted_soft') #self.temperature.useAdj('alt_fifty') #self.temperature.useAdj('average_alt') + self.temperature.useAdj('best') answers = {} for i in range(iterations): diff --git a/copycat/temperature.py b/copycat/temperature.py index 20aca17..e62f0a8 100644 --- a/copycat/temperature.py +++ b/copycat/temperature.py @@ -56,6 +56,12 @@ def _averaged_alt(temp, prob): u = prob ** 2 if prob < .5 else math.sqrt(prob) return _weighted(temp, prob, s, u) +def _working_best(temp, prob): + s = .5 # convergence + r = 1.05 # power + u = prob ** r if prob < .5 else prob ** (1/r) + return _weighted(temp, prob, s, u) + class Temperature(object): def __init__(self): self.reset() @@ -68,7 +74,8 @@ class Temperature(object): 'soft' : _soft_curve, 'weighted_soft' : _weighted_soft_curve, 'alt_fifty' : _alt_fifty, - 'average_alt' : _averaged_alt} + 'average_alt' : _averaged_alt, + 'best' : _working_best} def reset(self): self.actual_value = 100.0 From 1835367ea94f930ee24cf0382303bac4930d400a Mon Sep 17 00:00:00 2001 From: lsaldyt Date: Mon, 16 Oct 2017 13:41:47 -0700 Subject: [PATCH 5/5] Updates tests: All tests pass. --- tests.py | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/tests.py b/tests.py index b194b9a..04f0418 100644 --- a/tests.py +++ b/tests.py @@ -70,16 +70,13 @@ class TestCopycat(unittest.TestCase): def test_abc_xyz(self): self.run_testcase('abc', 'abd', 'xyz', 100, - {'dyz': {'avgtemp': 26.143509984937367, 'avgtime': 9866.625, 'count': 8}, - 'wyz': {'avgtemp': 12.249539212574128, - 'avgtime': 9520.666666666666, - 'count': 18}, - 'xyd': {'avgtemp': 38.73402068486291, 'avgtime': 7439.225, 'count': 40}, - 'xyy': {'avgtemp': 24.614440709519627, 'avgtime': 3522.625, 'count': 8}, - 'xyz': {'avgtemp': 57.674822842028945, 'avgtime': 8315.2, 'count': 5}, - 'yyz': {'avgtemp': 26.874886217740315, - 'avgtime': 8493.142857142857, - 'count': 21}}) + {'dyz': {'avgtemp': 16.78130739435325, 'avgtime': 393.0, 'count': 1}, + 'wyz': {'avgtemp': 26.100450643627426, 'avgtime': 4040.0, 'count': 2}, + 'xyd': {'avgtemp': 21.310415433987586, + 'avgtime': 5592.277777777777, + 'count': 90}, + 'xyz': {'avgtemp': 23.798124933747882, 'avgtime': 3992.0, 'count': 1}, + 'yyz': {'avgtemp': 27.137975077133788, 'avgtime': 4018.5, 'count': 6}}) def test_ambiguous_case(self): self.run_testcase('abc', 'abd', 'ijkk', 100, @@ -99,15 +96,12 @@ class TestCopycat(unittest.TestCase): def test_mrrjjj(self): self.run_testcase('abc', 'abd', 'mrrjjj', 30, - {'drrjjj': {'avgtemp': 47.3961, 'avgtime': 1538.0, 'count': 1}, - 'mrrjjd': {'avgtemp': 70.5363, 'avgtime': 681.0, 'count': 1}, - 'mrrjjjj': {'avgtemp': 19.1294, 'avgtime': 2075.0, 'count': 1}, - 'mrrjjk': {'avgtemp': 48.0952, - 'avgtime': 2203.5714, - 'count': 14}, - 'mrrkkk': {'avgtemp': 43.6931, - 'avgtime': 2251.4615, - 'count': 13}}) + {'mrrjjd': {'avgtemp': 44.46354725386579, 'avgtime': 1262.0, 'count': 1}, + 'mrrjjjj': {'avgtemp': 17.50702440140412, 'avgtime': 1038.375, 'count': 8}, + 'mrrjjk': {'avgtemp': 55.189156978290264, + 'avgtime': 1170.6363636363637, + 'count': 11}, + 'mrrkkk': {'avgtemp': 43.709349775080746, 'avgtime': 1376.2, 'count': 10}}) ''' Below are examples of improvements that could be made to copycat.