Skip to content

Commit

Permalink
merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
LSaldyt committed Jan 12, 2018
2 parents 9bf2980 + 54732b1 commit e877060
Show file tree
Hide file tree
Showing 38 changed files with 2,699 additions and 193 deletions.
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pip-log.txt
.coverage
.tox
.log
copycat.log

# Other filesystems
.svn
Expand All @@ -30,3 +31,13 @@ pip-log.txt

# Output
output/*
<<<<<<< HEAD
copycat.log
papers/*.log
papers/*.pdf
papers/*.out
papers/*.aux
papers/words
*.txt
=======
>>>>>>> develop
Binary file added .old_distributions
Binary file not shown.
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
co.py.cat
=========

I am planning to use this codebase, or Joseph A. Hager's, to implement a variation of Copycat that uses *Entropy* instead of *Temperature*, while still preserving the parallel terraced scan in full form. If the change is viable, I plan to write a paper on that (if anyone is interested in co-authoring, let me know). For the general idea, please see pages 41 and 42 of the [*Information Sciences*](https://github.com/Alex-Linhares/FARGlexandria/blob/master/Literature/Chess-Capyblanca-2014-Linhares-Information%20Sciences.pdf) paper on [Capyblanca](https://github.com/Alex-Linhares/FARGlexandria).
![GUI](https://i.imgur.com/7pb20g0.png)

**If you would like to help research and publish a paper, please let me know.**

Please see also [FARGlexandria](https://github.com/Alex-Linhares/FARGlexandria), a repository with all FARG projects (and help if you have some of the missing info there, especially about Letter Spirit and George!)

-------------------------------
An implementation of [Douglas Hofstadter](http://prelectur.stanford.edu/lecturers/hofstadter/)'s Copycat algorithm.
The Copycat algorithm is explained [on Wikipedia](https://en.wikipedia.org/wiki/Copycat_%28software%29), and that page has many links for deeper reading. See also [Farglexandria](https://github.com/Alex-Linhares/Farglexandria).

Expand Down
1 change: 1 addition & 0 deletions copycat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .copycat import Copycat, Reporter # noqa
from .problem import Problem
from .plot import plot_answers
from .io import save_answers
43 changes: 20 additions & 23 deletions copycat/copycat.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ def check_reset(self):

def mainLoop(self):
currentTime = self.coderack.codeletsRun
self.temperature.tryUnclamp(currentTime) # TODO: use entropy
# Every 15 codelets, we update the workspace.
if currentTime >= self.lastUpdate + 15:
self.temperature.tryUnclamp(currentTime)
# Every 5 codelets, we update the workspace.
if currentTime >= self.lastUpdate + 5:
self.update_workspace(currentTime)
self.step()

Expand Down Expand Up @@ -116,29 +116,26 @@ def runGUI(self):
return answers

def run(self, initial, modified, target, iterations):
self.temperature.useAdj('best')
self.workspace.resetWithStrings(initial, modified, target)
answers = {}
for formula in ['original', 'best', 'sbest', 'pbest']:
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']
print('The formula {} provided:'.format(formula))
pprint(answers)
formula = 'pbest'
self.temperature.useAdj(formula)
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']
print('The formula {} provided:'.format(formula))
print('Average difference: {}'.format(self.temperature.getAverageDifference()))
return answers

def run_forever(self, initial, modified, target):
Expand Down
3 changes: 3 additions & 0 deletions copycat/gui/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ def set_go(self):

def get_vars(self):
return self.entry.a.get(), self.entry.b.get(), self.entry.c.get()

def reset(self):
self.go = False
27 changes: 12 additions & 15 deletions copycat/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .list import List
from .style import configure_style

from .plot import plot_imbedded
from .plot import plot_answers, plot_temp

plt.style.use('dark_background')

Expand All @@ -40,10 +40,13 @@ def create_widgets(self):
self.add(self.codeletList, 1, 1)

self.objectList = List(self, columns)
self.add(self.objectList, 2, 1)
self.add(self.objectList, 2, 1, xspan=2)

self.graph1 = Plot(self, 'Temperature history')
self.add(self.graph1, 2, 0)

self.graph2 = Plot(self, 'Answer Distribution')
self.add(self.graph2, 2, 0)
self.add(self.graph2, 3, 0)

def update(self, copycat):
self.primary.update(copycat)
Expand All @@ -57,16 +60,11 @@ def update(self, copycat):
self.codeletList.update(codelets, key=lambda c:c.urgency, formatter= lambda s : '{}: {}'.format(s.name, round(s.urgency, 2)))
get_descriptors = lambda s : ', '.join('({}={})'.format(d.descriptionType.name, d.descriptor.name) for d in s.descriptions)
self.objectList.update(objects, formatter=lambda s : '{}: {}'.format(s, get_descriptors(s)))
'''
if len(objects) > 0:
print('Descriptions:')
for obj in objects:
print(obj)
for description in obj.descriptions:
print(' {}:'.format(description))
print(' {}'.format(description.descriptionType.name))
print(' {}'.format(description.descriptor.name))
'''

def modifier(status):
with plt.style.context(('dark_background')):
plot_temp(copycat.temperature, status)
self.graph1.status.modifier = modifier

def reset_with_strings(self, initial, modified, target):
self.primary.reset_with_strings(initial, modified, target)
Expand All @@ -79,13 +77,12 @@ def __init__(self, title):
tk.Grid.columnconfigure(self.root, 0, weight=1)
self.app = MainApplication(self.root)
self.app.grid(row=0, column=0, sticky=tk.N+tk.S+tk.E+tk.W)

configure_style(ttk.Style())

def add_answers(self, answers):
def modifier(status):
with plt.style.context(('dark_background')):
plot_imbedded(answers, status)
plot_answers(answers, status)
self.app.graph2.status.modifier = modifier

def refresh(self):
Expand Down
9 changes: 7 additions & 2 deletions copycat/gui/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
import numpy as np
import matplotlib.pyplot as plt

plt.style.use('dark_background')
def plot_temp(temperature, status):
status.subplot.clear()
status.subplot.plot(temperature.history)
status.subplot.set_ylabel('Temperature')
status.subplot.set_xlabel('Time')
status.subplot.set_title('Temperature History')

def plot_imbedded(answers, status):
def plot_answers(answers, status):
answers = sorted(answers.items(), key=lambda kv : kv[1]['count'])
objects = [t[0] for t in answers]
yvalues = [t[1]['count'] for t in answers]
Expand Down
1 change: 1 addition & 0 deletions copycat/gui/primary.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ def update(self, copycat):

def reset_with_strings(self, initial, modified, target):
self.canvas.reset_with_strings(initial, modified, target)
self.control.reset()
1 change: 1 addition & 0 deletions copycat/gui/workspacecanvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def __init__(self, parent, *args, **kwargs):
self.changed = False

self.canvas = tk.Canvas(self, background='black')
#self.canvas['width'] = 1600
self.add(self.canvas, 0, 0)

GridFrame.configure(self)
Expand Down
69 changes: 69 additions & 0 deletions copycat/problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from .copycat import Copycat

from pprint import pprint

class Problem:
def __init__(self, initial, modified, target, iterations, distributions=None, formulas=None):
self.formulas = formulas
if formulas is not None:
assert hasattr(Copycat(), 'temperature')
else:
if hasattr(Copycat(), 'temperature'):
self.formulas = set(Copycat().temperature.adj_formulas())
print(self.formulas)
self.initial = initial
self.modified = modified
self.target = target

self.iterations = iterations
if distributions is None:
self.distributions = self.solve()
else:
self.distributions = distributions
print(self.formulas)

def test(self, comparison, expected=None):
print('-' * 120)
print('Testing copycat problem: {} : {} :: {} : _'.format(self.initial,
self.modified,
self.target))
print('expected:')
if expected is None:
expected = self.distributions
pprint(expected)

actual = self.solve()
print('actual:')
pprint(actual)
comparison(actual, expected)
print('-' * 120)

def solve(self):
print('-' * 120)
print('Testing copycat problem: {} : {} :: {} : _'.format(self.initial,
self.modified,
self.target))
copycat = Copycat()
answers = dict()
if self.formulas == None:
if hasattr(copycat, 'temperature'):
formula = copycat.temperature.getAdj()
else:
formula = None
answers[formula] = copycat.run(self.initial,
self.modified,
self.target,
self.iterations)
else:
print(self.formulas)
for formula in self.formulas:
copycat.temperature.useAdj(formula)
answers[formula] = copycat.run(self.initial,
self.modified,
self.target,
self.iterations)
print('Done with {}'.format(formula))
return answers

def generate(self):
self.distributions = self.solve()
14 changes: 7 additions & 7 deletions copycat/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def updateInternalStrength(self):
return
averageDepth = (self.descriptor.conceptualDepth +
self.relation.conceptualDepth) / 2.0
averageDepth **= 1.1
averageDepth **= 1.1 # LSaldyt: This value (1.1) seems 100% contrived.
# see if the object corresponds to an object
# if so, see if the descriptor is present (modulo slippages) in the
# corresponding object
Expand All @@ -45,15 +45,15 @@ def updateInternalStrength(self):
self.internalStrength = 0.0
return
sharedDescriptorTerm = 100.0
conceptual_height = (100.0 - self.descriptor.conceptualDepth) / 10.0
sharedDescriptorWeight = conceptual_height ** 1.4
conceptual_height = (100.0 - self.descriptor.conceptualDepth) / 10.0 # LSaldyt: 10?
sharedDescriptorWeight = conceptual_height ** 1.4 # LSaldyt: 1.4 is also seemingly contrived
depthDifference = 100.0 - abs(self.descriptor.conceptualDepth -
self.relation.conceptualDepth)
weights = ((depthDifference, 12),
(averageDepth, 18),
(sharedDescriptorTerm, sharedDescriptorWeight))
weights = ((depthDifference, 12), # LSaldyt: ???
(averageDepth, 18), # ????
(sharedDescriptorTerm, sharedDescriptorWeight)) # 12 and 18 can be reduced to 2 and 3, depending on sharedDescriptorWeight
self.internalStrength = formulas.weightedAverage(weights)
if self.internalStrength > 100.0:
if self.internalStrength > 100.0: # LSaldyt: A better formula wouldn't need to do this.
self.internalStrength = 100.0

def ruleEqual(self, other):
Expand Down
Loading

0 comments on commit e877060

Please sign in to comment.