Merge branch 'develop'
This commit is contained in:
@ -22,7 +22,6 @@ def codelet(name):
|
|||||||
return f
|
return f
|
||||||
return wrap
|
return wrap
|
||||||
|
|
||||||
|
|
||||||
# some methods common to the codelets
|
# some methods common to the codelets
|
||||||
def __showWhichStringObjectIsFrom(structure):
|
def __showWhichStringObjectIsFrom(structure):
|
||||||
if not structure:
|
if not structure:
|
||||||
|
|||||||
@ -3,6 +3,10 @@ from .randomness import Randomness
|
|||||||
from .slipnet import Slipnet
|
from .slipnet import Slipnet
|
||||||
from .temperature import Temperature
|
from .temperature import Temperature
|
||||||
from .workspace import Workspace
|
from .workspace import Workspace
|
||||||
|
from .gui import GUI
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
|
||||||
class Reporter(object):
|
class Reporter(object):
|
||||||
"""Do-nothing base class for defining new reporter types"""
|
"""Do-nothing base class for defining new reporter types"""
|
||||||
@ -23,30 +27,48 @@ class Reporter(object):
|
|||||||
|
|
||||||
|
|
||||||
class Copycat(object):
|
class Copycat(object):
|
||||||
def __init__(self, rng_seed=None, reporter=None):
|
def __init__(self, rng_seed=None, reporter=None, gui=False):
|
||||||
self.coderack = Coderack(self)
|
self.coderack = Coderack(self)
|
||||||
self.random = Randomness(rng_seed)
|
self.random = Randomness(rng_seed)
|
||||||
self.slipnet = Slipnet()
|
self.slipnet = Slipnet()
|
||||||
self.temperature = Temperature() # TODO: use entropy
|
self.temperature = Temperature() # TODO: use entropy
|
||||||
self.workspace = Workspace(self)
|
self.workspace = Workspace(self)
|
||||||
self.reporter = reporter or Reporter()
|
self.reporter = reporter or Reporter()
|
||||||
|
if gui:
|
||||||
|
self.gui = GUI('Copycat')
|
||||||
|
self.lastUpdate = float('-inf')
|
||||||
|
|
||||||
def mainLoop(self, lastUpdate):
|
def step(self):
|
||||||
currentTime = self.coderack.codeletsRun
|
|
||||||
self.temperature.tryUnclamp(currentTime) # TODO: use entropy
|
|
||||||
# Every 15 codelets, we update the workspace.
|
|
||||||
if currentTime >= lastUpdate + 15:
|
|
||||||
self.workspace.updateEverything()
|
|
||||||
self.coderack.updateCodelets()
|
|
||||||
self.slipnet.update(self.random)
|
|
||||||
self.temperature.update(self.workspace.getUpdatedTemperature()) # TODO: use entropy
|
|
||||||
lastUpdate = currentTime
|
|
||||||
self.reporter.report_slipnet(self.slipnet)
|
|
||||||
self.coderack.chooseAndRunCodelet()
|
self.coderack.chooseAndRunCodelet()
|
||||||
self.reporter.report_coderack(self.coderack)
|
self.reporter.report_coderack(self.coderack)
|
||||||
self.reporter.report_temperature(self.temperature)
|
self.reporter.report_temperature(self.temperature)
|
||||||
self.reporter.report_workspace(self.workspace)
|
self.reporter.report_workspace(self.workspace)
|
||||||
return lastUpdate
|
|
||||||
|
def update_workspace(self, currentTime):
|
||||||
|
self.workspace.updateEverything()
|
||||||
|
self.coderack.updateCodelets()
|
||||||
|
self.slipnet.update(self.random)
|
||||||
|
self.temperature.update(self.workspace.getUpdatedTemperature())
|
||||||
|
self.lastUpdate = currentTime
|
||||||
|
self.reporter.report_slipnet(self.slipnet)
|
||||||
|
|
||||||
|
def check_reset(self):
|
||||||
|
if self.gui.app.primary.control.go:
|
||||||
|
initial, modified, target = self.gui.app.primary.control.get_vars()
|
||||||
|
self.gui.app.reset_with_strings(initial, modified, target)
|
||||||
|
self.workspace.resetWithStrings(initial, modified, target)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
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.update_workspace(currentTime)
|
||||||
|
self.step()
|
||||||
|
|
||||||
|
|
||||||
def runTrial(self):
|
def runTrial(self):
|
||||||
"""Run a trial of the copycat algorithm"""
|
"""Run a trial of the copycat algorithm"""
|
||||||
@ -54,9 +76,8 @@ class Copycat(object):
|
|||||||
self.slipnet.reset()
|
self.slipnet.reset()
|
||||||
self.temperature.reset() # TODO: use entropy
|
self.temperature.reset() # TODO: use entropy
|
||||||
self.workspace.reset()
|
self.workspace.reset()
|
||||||
lastUpdate = float('-inf')
|
|
||||||
while self.workspace.finalAnswer is None:
|
while self.workspace.finalAnswer is None:
|
||||||
lastUpdate = self.mainLoop(lastUpdate)
|
self.mainLoop()
|
||||||
answer = {
|
answer = {
|
||||||
'answer': self.workspace.finalAnswer,
|
'answer': self.workspace.finalAnswer,
|
||||||
'temp': self.temperature.last_unclamped_value, # TODO: use entropy
|
'temp': self.temperature.last_unclamped_value, # TODO: use entropy
|
||||||
@ -65,34 +86,60 @@ 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 runGUI(self):
|
||||||
self.workspace.resetWithStrings(initial, modified, target)
|
while not self.check_reset():
|
||||||
|
self.gui.update(self)
|
||||||
self.temperature.useAdj('original')
|
self.gui.refresh()
|
||||||
#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('alt_fifty')
|
|
||||||
#self.temperature.useAdj('average_alt')
|
|
||||||
self.temperature.useAdj('best')
|
|
||||||
|
|
||||||
answers = {}
|
answers = {}
|
||||||
for i in range(iterations):
|
self.temperature.useAdj('pbest')
|
||||||
answer = self.runTrial()
|
while True:
|
||||||
d = answers.setdefault(answer['answer'], {
|
if self.check_reset():
|
||||||
'count': 0,
|
answers = {}
|
||||||
'sumtemp': 0, # TODO: use entropy
|
self.gui.refresh()
|
||||||
'sumtime': 0
|
if not self.gui.paused():
|
||||||
})
|
answer = self.runTrial()
|
||||||
d['count'] += 1
|
self.gui.update(self)
|
||||||
d['sumtemp'] += answer['temp'] # TODO: use entropy
|
d = answers.setdefault(answer['answer'], {
|
||||||
d['sumtime'] += answer['time']
|
'count': 0,
|
||||||
|
'sumtemp': 0,
|
||||||
|
'sumtime': 0
|
||||||
|
})
|
||||||
|
d['count'] += 1
|
||||||
|
d['sumtemp'] += answer['temp']
|
||||||
|
d['sumtime'] += answer['time']
|
||||||
|
self.gui.add_answers(answers)
|
||||||
|
|
||||||
for answer, d in answers.items():
|
for answer, d in answers.items():
|
||||||
d['avgtemp'] = d.pop('sumtemp') / d['count']
|
d['avgtemp'] = d.pop('sumtemp') / d['count']
|
||||||
d['avgtime'] = d.pop('sumtime') / d['count']
|
d['avgtime'] = d.pop('sumtime') / d['count']
|
||||||
|
pprint(answers)
|
||||||
|
return answers
|
||||||
|
|
||||||
|
def run(self, initial, modified, target, iterations):
|
||||||
|
self.temperature.useAdj('best')
|
||||||
|
self.gui.app.reset_with_strings(initial, modified, target)
|
||||||
|
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)
|
||||||
|
|
||||||
return answers
|
return answers
|
||||||
|
|
||||||
def run_forever(self, initial, modified, target):
|
def run_forever(self, initial, modified, target):
|
||||||
|
|||||||
1
copycat/gui/__init__.py
Normal file
1
copycat/gui/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .gui import GUI
|
||||||
56
copycat/gui/control.py
Normal file
56
copycat/gui/control.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
from .gridframe import GridFrame
|
||||||
|
from .entry import Entry
|
||||||
|
|
||||||
|
class Control(GridFrame):
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
GridFrame.__init__(self, parent, *args, **kwargs)
|
||||||
|
|
||||||
|
self.paused = True
|
||||||
|
self.steps = 0
|
||||||
|
self.go = False
|
||||||
|
|
||||||
|
self.playbutton = ttk.Button(self, text='Play', command=lambda : self.toggle())
|
||||||
|
self.add(self.playbutton, 0, 0)
|
||||||
|
|
||||||
|
self.stepbutton = ttk.Button(self, text='Step', command=lambda : self.step())
|
||||||
|
self.add(self.stepbutton, 1, 0)
|
||||||
|
|
||||||
|
self.entry = Entry(self)
|
||||||
|
self.add(self.entry, 0, 1, xspan=2)
|
||||||
|
|
||||||
|
self.gobutton = ttk.Button(self, text='Go', command=lambda : self.set_go())
|
||||||
|
self.add(self.gobutton, 0, 2, xspan=2)
|
||||||
|
|
||||||
|
def play(self):
|
||||||
|
self.paused = False
|
||||||
|
self.playbutton['text'] = 'Pause'
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
self.paused = True
|
||||||
|
self.playbutton['text'] = 'Play'
|
||||||
|
|
||||||
|
def toggle(self):
|
||||||
|
if self.paused:
|
||||||
|
self.play()
|
||||||
|
else:
|
||||||
|
self.pause()
|
||||||
|
|
||||||
|
def step(self):
|
||||||
|
self.steps += 1
|
||||||
|
|
||||||
|
def has_step(self):
|
||||||
|
if self.steps > 0:
|
||||||
|
self.steps -= 1
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_go(self):
|
||||||
|
self.go = True
|
||||||
|
self.play()
|
||||||
|
|
||||||
|
def get_vars(self):
|
||||||
|
return self.entry.a.get(), self.entry.b.get(), self.entry.c.get()
|
||||||
27
copycat/gui/entry.py
Normal file
27
copycat/gui/entry.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
from .gridframe import GridFrame
|
||||||
|
|
||||||
|
class Entry(GridFrame):
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
GridFrame.__init__(self, parent, *args, **kwargs)
|
||||||
|
self.aLabel = ttk.Label(self, text='Initial:')
|
||||||
|
self.a = ttk.Entry(self, style='EntryStyle.TEntry')
|
||||||
|
|
||||||
|
self.add(self.aLabel, 0, 0)
|
||||||
|
self.add(self.a, 0, 1)
|
||||||
|
|
||||||
|
self.bLabel = ttk.Label(self, text='Final:')
|
||||||
|
self.b = ttk.Entry(self, style='EntryStyle.TEntry')
|
||||||
|
|
||||||
|
self.add(self.bLabel, 1, 0)
|
||||||
|
self.add(self.b, 1, 1)
|
||||||
|
|
||||||
|
self.cLabel = ttk.Label(self, text='Next:')
|
||||||
|
self.c = ttk.Entry(self, style='EntryStyle.TEntry')
|
||||||
|
|
||||||
|
self.add(self.cLabel, 2, 0)
|
||||||
|
self.add(self.c, 2, 1)
|
||||||
|
GridFrame.configure(self)
|
||||||
11
copycat/gui/gridframe.py
Normal file
11
copycat/gui/gridframe.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
class GridFrame(tk.Frame):
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
ttk.Frame.__init__(self, parent, *args, **kwargs)
|
||||||
|
|
||||||
|
def add(self, element, x, y, xspan=1, yspan=1):
|
||||||
|
element.grid(column=x, row=y, columnspan=xspan, rowspan=yspan, sticky=tk.N+tk.E+tk.S+tk.W)
|
||||||
|
tk.Grid.rowconfigure(self, x, weight=1)
|
||||||
|
tk.Grid.columnconfigure(self, y, weight=1)
|
||||||
99
copycat/gui/gui.py
Normal file
99
copycat/gui/gui.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
from tkinter import scrolledtext
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
from .status import Status, StatusFrame
|
||||||
|
from .status import Plot
|
||||||
|
from .gridframe import GridFrame
|
||||||
|
from .primary import Primary
|
||||||
|
from .list import List
|
||||||
|
from .style import configure_style
|
||||||
|
|
||||||
|
from .plot import plot_imbedded
|
||||||
|
|
||||||
|
plt.style.use('dark_background')
|
||||||
|
|
||||||
|
class MainApplication(GridFrame):
|
||||||
|
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
GridFrame.__init__(self, parent, *args, **kwargs)
|
||||||
|
|
||||||
|
self.parent = parent
|
||||||
|
self.primary = Primary(self, *args, **kwargs)
|
||||||
|
self.add(self.primary, 0, 0, xspan=2)
|
||||||
|
self.create_widgets()
|
||||||
|
GridFrame.configure(self)
|
||||||
|
|
||||||
|
def create_widgets(self):
|
||||||
|
columns = 20
|
||||||
|
self.slipList = List(self, columns)
|
||||||
|
self.add(self.slipList, 0, 1)
|
||||||
|
|
||||||
|
self.codeletList = List(self, columns)
|
||||||
|
self.add(self.codeletList, 1, 1)
|
||||||
|
|
||||||
|
self.objectList = List(self, columns)
|
||||||
|
self.add(self.objectList, 2, 1)
|
||||||
|
|
||||||
|
self.graph2 = Plot(self, 'Answer Distribution')
|
||||||
|
self.add(self.graph2, 2, 0)
|
||||||
|
|
||||||
|
def update(self, copycat):
|
||||||
|
self.primary.update(copycat)
|
||||||
|
|
||||||
|
slipnodes = copycat.slipnet.slipnodes
|
||||||
|
codelets = copycat.coderack.codelets
|
||||||
|
objects = copycat.workspace.objects
|
||||||
|
|
||||||
|
self.slipList.update(slipnodes, key=lambda s:s.activation,
|
||||||
|
formatter=lambda s : '{}: {}'.format(s.name, round(s.activation, 2)))
|
||||||
|
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 reset_with_strings(self, initial, modified, target):
|
||||||
|
self.primary.reset_with_strings(initial, modified, target)
|
||||||
|
|
||||||
|
class GUI(object):
|
||||||
|
def __init__(self, title):
|
||||||
|
self.root = tk.Tk()
|
||||||
|
self.root.title(title)
|
||||||
|
tk.Grid.rowconfigure(self.root, 0, weight=1)
|
||||||
|
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)
|
||||||
|
self.app.graph2.status.modifier = modifier
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self.root.update_idletasks()
|
||||||
|
self.root.update()
|
||||||
|
|
||||||
|
def paused(self):
|
||||||
|
return self.app.primary.control.paused
|
||||||
|
|
||||||
|
def update(self, copycat):
|
||||||
|
self.app.update(copycat)
|
||||||
26
copycat/gui/list.py
Normal file
26
copycat/gui/list.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from .gridframe import GridFrame
|
||||||
|
|
||||||
|
class List(GridFrame):
|
||||||
|
|
||||||
|
def __init__(self, parent, columns, updateInterval=.1):
|
||||||
|
GridFrame.__init__(self, parent)
|
||||||
|
self.text = ttk.Label(self, anchor='w', justify=tk.LEFT, width=30)
|
||||||
|
self.add(self.text, 0, 0)
|
||||||
|
|
||||||
|
self.columns = columns
|
||||||
|
|
||||||
|
self.lastUpdated = time.time()
|
||||||
|
self.updateInterval = updateInterval
|
||||||
|
|
||||||
|
def update(self, l, key=None, reverse=False, formatter=lambda s : str(s)):
|
||||||
|
current = time.time()
|
||||||
|
if current - self.lastUpdated > self.updateInterval:
|
||||||
|
l = l[:self.columns]
|
||||||
|
if key is not None:
|
||||||
|
l = sorted(l, key=key, reverse=False)
|
||||||
|
self.text['text'] = '\n'.join(map(formatter, l))
|
||||||
19
copycat/gui/plot.py
Normal file
19
copycat/gui/plot.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import matplotlib.pyplot as plt; plt.rcdefaults()
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
plt.style.use('dark_background')
|
||||||
|
|
||||||
|
def plot_imbedded(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]
|
||||||
|
|
||||||
|
y_pos = np.arange(len(objects))
|
||||||
|
|
||||||
|
status.subplot.clear()
|
||||||
|
status.subplot.bar(y_pos, yvalues, align='center', alpha=0.5)
|
||||||
|
status.subplot.set_xticks(y_pos)
|
||||||
|
status.subplot.set_xticklabels(tuple(objects))
|
||||||
|
status.subplot.set_ylabel('Count')
|
||||||
|
status.subplot.set_title('Answers')
|
||||||
29
copycat/gui/primary.py
Normal file
29
copycat/gui/primary.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
from tkinter import scrolledtext
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
from .control import Control
|
||||||
|
from .gridframe import GridFrame
|
||||||
|
|
||||||
|
from .workspacecanvas import WorkspaceCanvas
|
||||||
|
|
||||||
|
class Primary(GridFrame):
|
||||||
|
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
GridFrame.__init__(self, parent, *args, **kwargs)
|
||||||
|
|
||||||
|
self.canvas = WorkspaceCanvas(self)
|
||||||
|
self.add(self.canvas, 0, 0, xspan=2)
|
||||||
|
|
||||||
|
self.control = Control(self)
|
||||||
|
self.add(self.control, 0, 2)
|
||||||
|
|
||||||
|
GridFrame.configure(self)
|
||||||
|
|
||||||
|
def update(self, copycat):
|
||||||
|
self.canvas.update(copycat)
|
||||||
|
|
||||||
|
def reset_with_strings(self, initial, modified, target):
|
||||||
|
self.canvas.reset_with_strings(initial, modified, target)
|
||||||
66
copycat/gui/status.py
Normal file
66
copycat/gui/status.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import matplotlib
|
||||||
|
matplotlib.use("TkAgg")
|
||||||
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
import time
|
||||||
|
import matplotlib.animation as animation
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
plt.style.use('dark_background')
|
||||||
|
|
||||||
|
from .gridframe import GridFrame
|
||||||
|
|
||||||
|
class Plot(GridFrame):
|
||||||
|
def __init__(self, parent, title):
|
||||||
|
GridFrame.__init__(self, parent)
|
||||||
|
self.status = Status()
|
||||||
|
self.sframe = StatusFrame(self, self.status, title)
|
||||||
|
self.add(self.sframe, 0, 0, xspan=2)
|
||||||
|
|
||||||
|
self.savebutton = ttk.Button(self, text='Save to path:', command=lambda : self.save())
|
||||||
|
self.add(self.savebutton, 0, 1)
|
||||||
|
|
||||||
|
self.pathentry = ttk.Entry(self, style='EntryStyle.TEntry', textvariable='output/dist.png')
|
||||||
|
self.add(self.pathentry, 1, 1)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
path = self.pathentry.get()
|
||||||
|
if len(path) > 0:
|
||||||
|
try:
|
||||||
|
self.status.figure.savefig(path)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
class StatusFrame(ttk.Frame):
|
||||||
|
def __init__(self, parent, status, title):
|
||||||
|
ttk.Frame.__init__(self, parent)
|
||||||
|
self.status = status
|
||||||
|
|
||||||
|
self.canvas = FigureCanvasTkAgg(status.figure, self)
|
||||||
|
self.canvas.show()
|
||||||
|
self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
self.animation = animation.FuncAnimation(status.figure, lambda i : status.update_plots(i), interval=1000)
|
||||||
|
|
||||||
|
class Status(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.figure = Figure(figsize=(5,5), dpi=100)
|
||||||
|
self.subplot = self.figure.add_subplot(111)
|
||||||
|
self.x = []
|
||||||
|
self.y = []
|
||||||
|
|
||||||
|
def modifier(status):
|
||||||
|
with plt.style.context(('dark_background')):
|
||||||
|
status.subplot.plot(status.x, status.y)
|
||||||
|
|
||||||
|
self.modifier = modifier
|
||||||
|
self.update_plots(0)
|
||||||
|
|
||||||
|
def update_plots(self, i):
|
||||||
|
self.subplot.clear()
|
||||||
|
self.modifier(self)
|
||||||
33
copycat/gui/style.py
Normal file
33
copycat/gui/style.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
style_dict = dict(foreground='white',
|
||||||
|
background='black')
|
||||||
|
|
||||||
|
map_options = dict(
|
||||||
|
foreground=[('disabled', 'black'),
|
||||||
|
('pressed', 'white'),
|
||||||
|
('active', 'white')],
|
||||||
|
background=[('disabled', 'black'),
|
||||||
|
('pressed', '!focus', 'black'),
|
||||||
|
('active', 'black')],
|
||||||
|
highlightcolor=[('focus', 'black'),
|
||||||
|
('!focus', 'black')])
|
||||||
|
|
||||||
|
def configure_style(style):
|
||||||
|
style.configure('TButton', **style_dict)
|
||||||
|
style.map('TButton', **map_options)
|
||||||
|
style.configure('TLabel', **style_dict)
|
||||||
|
#style.configure('TEntry', **style_dict)
|
||||||
|
#style.map('TEntry', **map_options)
|
||||||
|
|
||||||
|
# A hack to change entry style
|
||||||
|
style.element_create("plain.field", "from", "clam")
|
||||||
|
style.layout("EntryStyle.TEntry",
|
||||||
|
[('Entry.plain.field', {'children': [(
|
||||||
|
'Entry.background', {'children': [(
|
||||||
|
'Entry.padding', {'children': [(
|
||||||
|
'Entry.textarea', {'sticky': 'nswe'})],
|
||||||
|
'sticky': 'nswe'})], 'sticky': 'nswe'})],
|
||||||
|
'border':'2', 'sticky': 'nswe'})])
|
||||||
|
style.configure("EntryStyle.TEntry",
|
||||||
|
background="black",
|
||||||
|
foreground="white",
|
||||||
|
fieldbackground="black")
|
||||||
159787
copycat/gui/sys
Normal file
159787
copycat/gui/sys
Normal file
File diff suppressed because it is too large
Load Diff
3093
copycat/gui/time
Normal file
3093
copycat/gui/time
Normal file
File diff suppressed because it is too large
Load Diff
69
copycat/gui/workspacecanvas.py
Normal file
69
copycat/gui/workspacecanvas.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
|
||||||
|
from .gridframe import GridFrame
|
||||||
|
|
||||||
|
font1Size = 32
|
||||||
|
font1 = ('Helvetica', font1Size)
|
||||||
|
|
||||||
|
class WorkspaceCanvas(GridFrame):
|
||||||
|
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
GridFrame.__init__(self, parent, *args, **kwargs)
|
||||||
|
|
||||||
|
self.chars = []
|
||||||
|
|
||||||
|
self.initial = ''
|
||||||
|
self.modified = ''
|
||||||
|
self.target = ''
|
||||||
|
self.answer = ''
|
||||||
|
|
||||||
|
self.changed = False
|
||||||
|
|
||||||
|
self.canvas = tk.Canvas(self, background='black')
|
||||||
|
self.add(self.canvas, 0, 0)
|
||||||
|
|
||||||
|
GridFrame.configure(self)
|
||||||
|
|
||||||
|
def update(self, copycat):
|
||||||
|
answer = '' if copycat.workspace.rule is None else copycat.workspace.rule.buildTranslatedRule()
|
||||||
|
if answer != self.answer:
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
if self.changed:
|
||||||
|
self.canvas.delete('all')
|
||||||
|
del self.chars[:]
|
||||||
|
self.add_text()
|
||||||
|
|
||||||
|
def add_text(self):
|
||||||
|
padding = 100
|
||||||
|
|
||||||
|
def add_sequences(sequences, x, y):
|
||||||
|
for sequence in sequences:
|
||||||
|
x += padding
|
||||||
|
if sequence is None:
|
||||||
|
sequence = ''
|
||||||
|
for char in sequence:
|
||||||
|
self.chars.append((char, (x, y)))
|
||||||
|
self.canvas.create_text(x, y, text=char, anchor=tk.NW, font=font1, fill='white')
|
||||||
|
x += font1Size
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
x = 0
|
||||||
|
y = padding
|
||||||
|
|
||||||
|
add_sequences([self.initial, self.modified], x, y)
|
||||||
|
|
||||||
|
x = 0
|
||||||
|
y += padding
|
||||||
|
|
||||||
|
add_sequences([self.target, self.answer], x, y)
|
||||||
|
|
||||||
|
def reset_with_strings(self, initial, modified, target):
|
||||||
|
if initial != self.initial or \
|
||||||
|
modified != self.modified or \
|
||||||
|
target != self.target:
|
||||||
|
self.changed = True
|
||||||
|
self.initial = initial
|
||||||
|
self.modified = modified
|
||||||
|
self.target = target
|
||||||
4
copycat/sampleText.txt
Normal file
4
copycat/sampleText.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1,2
|
||||||
|
3,4
|
||||||
|
7,7
|
||||||
|
100,100
|
||||||
@ -24,7 +24,7 @@ def _entropy(temp, prob):
|
|||||||
f = (c + 1) * prob
|
f = (c + 1) * prob
|
||||||
return -f * math.log2(f)
|
return -f * math.log2(f)
|
||||||
|
|
||||||
def _weighted(temp, prob, s, u):
|
def _weighted(temp, prob, s, u, alpha=1, beta=1):
|
||||||
weighted = (temp / 100) * s + ((100 - temp) / 100) * u
|
weighted = (temp / 100) * s + ((100 - temp) / 100) * u
|
||||||
return weighted
|
return weighted
|
||||||
|
|
||||||
@ -56,12 +56,31 @@ def _averaged_alt(temp, prob):
|
|||||||
u = prob ** 2 if prob < .5 else math.sqrt(prob)
|
u = prob ** 2 if prob < .5 else math.sqrt(prob)
|
||||||
return _weighted(temp, prob, s, u)
|
return _weighted(temp, prob, s, u)
|
||||||
|
|
||||||
|
|
||||||
def _working_best(temp, prob):
|
def _working_best(temp, prob):
|
||||||
|
s = .5 # convergence
|
||||||
|
r = 2 # power
|
||||||
|
u = prob ** r if prob < .5 else prob ** (1/r)
|
||||||
|
return _weighted(temp, prob, s, u)
|
||||||
|
|
||||||
|
def _soft_best(temp, prob):
|
||||||
s = .5 # convergence
|
s = .5 # convergence
|
||||||
r = 1.05 # power
|
r = 1.05 # power
|
||||||
u = prob ** r if prob < .5 else prob ** (1/r)
|
u = prob ** r if prob < .5 else prob ** (1/r)
|
||||||
return _weighted(temp, prob, s, u)
|
return _weighted(temp, prob, s, u)
|
||||||
|
|
||||||
|
def _parameterized_best(temp, prob):
|
||||||
|
# (D$66/100)*($E$64*$B68 + $G$64*$F$64)/($E$64 + $G$64)+((100-D$66)/100)*IF($B68 > 0.5, $B68^(1/$H$64), $B68^$H$64)
|
||||||
|
# (T/100) * (alpha * p + beta * .5) / (alpha + beta) + ((100 - T)/100) * IF(p > .5, p^(1/2), p^2)
|
||||||
|
alpha = 5
|
||||||
|
beta = 1
|
||||||
|
s = .5
|
||||||
|
s = (alpha * prob + beta * s) / (alpha + beta)
|
||||||
|
r = 1.05
|
||||||
|
u = prob ** r if prob < .5 else prob ** (1/r)
|
||||||
|
return _weighted(temp, prob, s, u)
|
||||||
|
|
||||||
|
|
||||||
class Temperature(object):
|
class Temperature(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
@ -75,7 +94,9 @@ class Temperature(object):
|
|||||||
'weighted_soft' : _weighted_soft_curve,
|
'weighted_soft' : _weighted_soft_curve,
|
||||||
'alt_fifty' : _alt_fifty,
|
'alt_fifty' : _alt_fifty,
|
||||||
'average_alt' : _averaged_alt,
|
'average_alt' : _averaged_alt,
|
||||||
'best' : _working_best}
|
'best' : _working_best,
|
||||||
|
'sbest' : _soft_best,
|
||||||
|
'pbest' : _parameterized_best}
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.actual_value = 100.0
|
self.actual_value = 100.0
|
||||||
|
|||||||
@ -23,6 +23,16 @@ class Workspace(object):
|
|||||||
self.intraStringUnhappiness = 0.0
|
self.intraStringUnhappiness = 0.0
|
||||||
self.interStringUnhappiness = 0.0
|
self.interStringUnhappiness = 0.0
|
||||||
|
|
||||||
|
# LSaldyt: default initializations for GUI entry
|
||||||
|
self.targetString = ''
|
||||||
|
self.initialString = ''
|
||||||
|
self.modifiedString = ''
|
||||||
|
self.finalAnswer = None
|
||||||
|
self.changedObject = None
|
||||||
|
self.objects = []
|
||||||
|
self.structures = []
|
||||||
|
self.rule = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Workspace trying %s:%s::%s:?>' % (
|
return '<Workspace trying %s:%s::%s:?>' % (
|
||||||
self.initialString, self.modifiedString, self.targetString,
|
self.initialString, self.modifiedString, self.targetString,
|
||||||
|
|||||||
28
gui.py
Executable file
28
gui.py
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copycat import Copycat, Reporter
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
plt.style.use('dark_background')
|
||||||
|
|
||||||
|
class SimpleReporter(Reporter):
|
||||||
|
def report_answer(self, answer):
|
||||||
|
print('Answered %s (time %d, final temperature %.1f)' % (
|
||||||
|
answer['answer'], answer['time'], answer['temp'],
|
||||||
|
))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(message)s', filename='./output/copycat.log', filemode='w')
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--seed', type=int, default=None, help='Provide a deterministic seed for the RNG.')
|
||||||
|
options = parser.parse_args()
|
||||||
|
|
||||||
|
copycat = Copycat(reporter=SimpleReporter(), rng_seed=options.seed, gui=True)
|
||||||
|
copycat.runGUI()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user