Merge pull request #1 from LSaldyt/master

Ports to Python3
This commit is contained in:
Alexandre Linhares
2017-08-27 12:37:36 -03:00
committed by GitHub
22 changed files with 158 additions and 92 deletions

63
copycat.log Normal file
View File

@ -0,0 +1,63 @@
object chosen = j from target string
destination: k
chosen bond facet: letterCategory
Source: j, destination: k
source descriptor: J
destination descriptor: K
proposing successor bond
urgency: 100.0, number: 1, bin: 7
object chosen = j from target string
destination: i
chosen bond facet: letterCategory
Source: j, destination: i
source descriptor: J
destination descriptor: I
proposing predecessor bond
object chosen = successor bond between j and k from other string
bond strength = 48 for successor bond between j and k
object chosen = a from initial string
destination: b
chosen bond facet: letterCategory
Source: a, destination: b
source descriptor: A
destination descriptor: B
proposing successor bond
object chosen = successor bond between a and b from other string
bond strength = 48 for successor bond between a and b
succeeded: posting bond-builder
object chosen = successor bond between a and b from other string
number of incompatibleBonds: 0
no incompatible bonds
no incompatible groups
building bond successor bond between a and b
object chosen = a from initial string
destination: b
chosen bond facet: letterCategory
Source: a, destination: b
source descriptor: A
destination descriptor: B
proposing successor bond
object chosen = a from initial string
destination: b
chosen bond facet: letterCategory
Source: a, destination: b
source descriptor: A
destination descriptor: B
proposing successor bond
Post top down: top-down-description-scout, with urgency: 5
posting bottom up codelets
object chosen = a from initial string
object chosen = j from target string
destination: i
chosen bond facet: letterCategory
Source: j, destination: i
source descriptor: J
destination descriptor: I
proposing predecessor bond
object chosen = a from initial string
destination: b
chosen bond facet: letterCategory
Source: a, destination: b
source descriptor: A
destination descriptor: B
proposing successor bond

View File

@ -1 +1 @@
from copycat import Copycat, Reporter # noqa from .copycat import Copycat, Reporter # noqa

View File

@ -1,4 +1,4 @@
from workspaceStructure import WorkspaceStructure from .workspaceStructure import WorkspaceStructure
class Bond(WorkspaceStructure): class Bond(WorkspaceStructure):

View File

@ -1,16 +1,16 @@
import inspect import inspect
import logging import logging
import formulas from . import formulas
from workspaceFormulas import chooseDirectedNeighbor from .workspaceFormulas import chooseDirectedNeighbor
from workspaceFormulas import chooseNeighbor from .workspaceFormulas import chooseNeighbor
from workspaceFormulas import chooseUnmodifiedObject from .workspaceFormulas import chooseUnmodifiedObject
from workspaceObject import WorkspaceObject from .workspaceObject import WorkspaceObject
from letter import Letter from .letter import Letter
from replacement import Replacement from .replacement import Replacement
from group import Group from .group import Group
from bond import Bond from .bond import Bond
from correspondence import Correspondence from .correspondence import Correspondence
def codelet(name): def codelet(name):
@ -804,7 +804,7 @@ def group_builder(ctx, codelet):
incompatible.break_the_structure() incompatible.break_the_structure()
# create new bonds # create new bonds
group.bondList = [] group.bondList = []
for i in xrange(1, len(group.objectList)): for i in range(1, len(group.objectList)):
object1 = group.objectList[i - 1] object1 = group.objectList[i - 1]
object2 = group.objectList[i] object2 = group.objectList[i]
if not object1.rightBond: if not object1.rightBond:
@ -871,7 +871,7 @@ def rule_translator(ctx, codelet):
bondDensity = numberOfBonds / nearlyTotalLength bondDensity = numberOfBonds / nearlyTotalLength
bondDensity = min(bondDensity, 1.0) bondDensity = min(bondDensity, 1.0)
weights = __getCutoffWeights(bondDensity) weights = __getCutoffWeights(bondDensity)
cutoff = 10.0 * random.weighted_choice(range(1, 11), weights) cutoff = 10.0 * random.weighted_choice(list(range(1, 11)), weights)
if cutoff >= temperature.actual_value: if cutoff >= temperature.actual_value:
result = workspace.rule.buildTranslatedRule() result = workspace.rule.buildTranslatedRule()
if result is not None: if result is not None:

View File

@ -1,13 +1,13 @@
import math import math
import logging import logging
import codeletMethods from . import codeletMethods
from bond import Bond from .bond import Bond
from codelet import Codelet from .codelet import Codelet
from correspondence import Correspondence from .correspondence import Correspondence
from description import Description from .description import Description
from group import Group from .group import Group
from rule import Rule from .rule import Rule
NUMBER_OF_BINS = 7 NUMBER_OF_BINS = 7
@ -131,7 +131,7 @@ class Coderack(object):
for codeletName in node.codelets: for codeletName in node.codelets:
probability = self.probabilityOfPosting(codeletName) probability = self.probabilityOfPosting(codeletName)
howMany = self.howManyToPost(codeletName) howMany = self.howManyToPost(codeletName)
for _ in xrange(howMany): for _ in range(howMany):
if not random.coinFlip(probability): if not random.coinFlip(probability):
continue continue
urgency = getUrgencyBin( urgency = getUrgencyBin(
@ -163,7 +163,7 @@ class Coderack(object):
urgency = 1 urgency = 1
if temperature.value() < 25.0 and 'translator' in codeletName: if temperature.value() < 25.0 and 'translator' in codeletName:
urgency = 5 urgency = 5
for _ in xrange(howMany): for _ in range(howMany):
if random.coinFlip(probability): if random.coinFlip(probability):
codelet = Codelet(codeletName, urgency, [], self.codeletsRun) codelet = Codelet(codeletName, urgency, [], self.codeletsRun)
self.post(codelet) self.post(codelet)
@ -272,7 +272,7 @@ class Coderack(object):
('bottom-up-correspondence-scout', 2 * n), ('bottom-up-correspondence-scout', 2 * n),
] ]
for name, count in codeletsToPost: for name, count in codeletsToPost:
for _ in xrange(count): for _ in range(count):
codelet = Codelet(name, 1, [], self.codeletsRun) codelet = Codelet(name, 1, [], self.codeletsRun)
self.post(codelet) self.post(codelet)

View File

@ -1,8 +1,8 @@
from coderack import Coderack from .coderack import Coderack
from randomness import Randomness 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
class Reporter(object): class Reporter(object):
@ -69,7 +69,7 @@ class Copycat(object):
def run(self, initial, modified, target, iterations): def run(self, initial, modified, target, iterations):
self.workspace.resetWithStrings(initial, modified, target) self.workspace.resetWithStrings(initial, modified, target)
answers = {} answers = {}
for i in xrange(iterations): for i in range(iterations):
answer = self.runTrial() answer = self.runTrial()
d = answers.setdefault(answer['answer'], { d = answers.setdefault(answer['answer'], {
'count': 0, 'count': 0,
@ -80,7 +80,7 @@ class Copycat(object):
d['sumtemp'] += answer['temp'] d['sumtemp'] += answer['temp']
d['sumtime'] += answer['time'] d['sumtime'] += answer['time']
for answer, d in answers.iteritems(): 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']
return answers return answers

View File

@ -1,8 +1,8 @@
from conceptMapping import ConceptMapping from .conceptMapping import ConceptMapping
from group import Group from .group import Group
from letter import Letter from .letter import Letter
from workspaceStructure import WorkspaceStructure from .workspaceStructure import WorkspaceStructure
import formulas from . import formulas
class Correspondence(WorkspaceStructure): class Correspondence(WorkspaceStructure):
@ -143,8 +143,8 @@ class Correspondence(WorkspaceStructure):
def internallyCoherent(self): def internallyCoherent(self):
"""Whether any pair of distinguishing mappings support each other""" """Whether any pair of distinguishing mappings support each other"""
mappings = self.relevantDistinguishingConceptMappings() mappings = self.relevantDistinguishingConceptMappings()
for i in xrange(len(mappings)): for i in range(len(mappings)):
for j in xrange(len(mappings)): for j in range(len(mappings)):
if i != j: if i != j:
if mappings[i].supports(mappings[j]): if mappings[i].supports(mappings[j]):
return True return True

View File

@ -1,13 +1,13 @@
import curses import curses
import time import time
from copycat import Reporter from .copycat import Reporter
from bond import Bond from .bond import Bond
from correspondence import Correspondence from .correspondence import Correspondence
from description import Description from .description import Description
from group import Group from .group import Group
from letter import Letter from .letter import Letter
from rule import Rule from .rule import Rule
class SafeSubwindow(object): class SafeSubwindow(object):
@ -122,7 +122,7 @@ class CursesReporter(Reporter):
d['answer'], d['count'], d['avgtime'], d['avgtemp'], d['answer'], d['count'], d['avgtime'], d['avgtemp'],
) )
answersToPrint = sorted(self.answers.itervalues(), key=fitness, reverse=True) answersToPrint = sorted(iter(self.answers.values()), key=fitness, reverse=True)
w = self.answersWindow w = self.answersWindow
pageWidth = w.getmaxyx()[1] pageWidth = w.getmaxyx()[1]
@ -175,7 +175,7 @@ class CursesReporter(Reporter):
# Sort the most common and highest-urgency codelets to the top. # Sort the most common and highest-urgency codelets to the top.
entries = sorted( entries = sorted(
(count, key[0], key[1]) (count, key[0], key[1])
for key, count in counts.iteritems() for key, count in counts.items()
) )
# Figure out how we'd like to render each codelet's name. # Figure out how we'd like to render each codelet's name.
@ -193,10 +193,10 @@ class CursesReporter(Reporter):
w.erase() w.erase()
for u, string in printable_entries: for u, string in printable_entries:
# Find the highest point on the page where we could place this entry. # Find the highest point on the page where we could place this entry.
start_column = (u - 1) * columnWidth start_column = int((u - 1) * columnWidth)
end_column = start_column + len(string) end_column = start_column + len(string)
for r in range(pageHeight): for r in range(pageHeight):
if all(w.is_vacant(r, c) for c in xrange(start_column, end_column+20)): if all(w.is_vacant(r, c) for c in range(start_column, end_column+20)):
w.addstr(r, start_column, string) w.addstr(r, start_column, string)
break break
w.refresh() w.refresh()
@ -308,7 +308,7 @@ class CursesReporter(Reporter):
else: else:
w.addstr(firstrow, column, '\\', curses.A_NORMAL) w.addstr(firstrow, column, '\\', curses.A_NORMAL)
w.addstr(lastrow, column, '/', curses.A_NORMAL) w.addstr(lastrow, column, '/', curses.A_NORMAL)
for r in xrange(firstrow + 1, lastrow): for r in range(firstrow + 1, lastrow):
w.addstr(r, column, '|', curses.A_NORMAL) w.addstr(r, column, '|', curses.A_NORMAL)
def report_workspace(self, workspace): def report_workspace(self, workspace):
@ -410,12 +410,12 @@ class CursesReporter(Reporter):
end = endrow_for_group[group] end = endrow_for_group[group]
# Place this group's graphical depiction. # Place this group's graphical depiction.
depiction_width = 3 + self.length_of_workspace_object_depiction(group, description_structures) depiction_width = 3 + self.length_of_workspace_object_depiction(group, description_structures)
for firstcolumn in xrange(max_column, 1000): for firstcolumn in range(max_column, 1000):
lastcolumn = firstcolumn + depiction_width lastcolumn = firstcolumn + depiction_width
okay = all( okay = all(
w.is_vacant(r, c) w.is_vacant(r, c)
for c in xrange(firstcolumn, lastcolumn + 1) for c in range(firstcolumn, lastcolumn + 1)
for r in xrange(start, end + 1) for r in range(start, end + 1)
) )
if okay: if okay:
self.depict_grouping_brace(w, start, end, firstcolumn + 1) self.depict_grouping_brace(w, start, end, firstcolumn + 1)

View File

@ -1,4 +1,4 @@
from workspaceStructure import WorkspaceStructure from .workspaceStructure import WorkspaceStructure
class Description(WorkspaceStructure): class Description(WorkspaceStructure):

View File

@ -1,4 +1,4 @@
from conceptMapping import ConceptMapping from .conceptMapping import ConceptMapping
def weightedAverage(values): def weightedAverage(values):

View File

@ -1,6 +1,6 @@
from description import Description from .description import Description
from workspaceObject import WorkspaceObject from .workspaceObject import WorkspaceObject
import formulas from . import formulas
class Group(WorkspaceObject): class Group(WorkspaceObject):

View File

@ -1,4 +1,4 @@
from workspaceObject import WorkspaceObject from .workspaceObject import WorkspaceObject
class Letter(WorkspaceObject): class Letter(WorkspaceObject):

View File

@ -1,4 +1,4 @@
from workspaceStructure import WorkspaceStructure from .workspaceStructure import WorkspaceStructure
class Replacement(WorkspaceStructure): class Replacement(WorkspaceStructure):

View File

@ -1,8 +1,8 @@
import logging import logging
from workspaceStructure import WorkspaceStructure from .workspaceStructure import WorkspaceStructure
import formulas from . import formulas
class Rule(WorkspaceStructure): class Rule(WorkspaceStructure):

View File

@ -1,5 +1,5 @@
from slipnode import Slipnode from .slipnode import Slipnode
from sliplink import Sliplink from .sliplink import Sliplink
class Slipnet(object): class Slipnet(object):

View File

@ -1,6 +1,6 @@
import unittest import unittest
from copycat import Copycat from .copycat import Copycat
def pnormaldist(p): def pnormaldist(p):
@ -20,7 +20,7 @@ def pnormaldist(p):
0.99999999: 5.7307, 0.99999999: 5.7307,
0.999999999: 6.1094, 0.999999999: 6.1094,
} }
return max(v for k, v in table.iteritems() if k <= p) return max(v for k, v in table.items() if k <= p)
def lower_bound_on_probability(hits, attempts, confidence=0.95): def lower_bound_on_probability(hits, attempts, confidence=0.95):
@ -44,11 +44,11 @@ class TestCopycat(unittest.TestCase):
self.longMessage = True # new in Python 2.7 self.longMessage = True # new in Python 2.7
def assertProbabilitiesLookRoughlyLike(self, actual, expected): def assertProbabilitiesLookRoughlyLike(self, actual, expected):
actual_count = 0.0 + sum(d['count'] for d in actual.values()) actual_count = 0.0 + sum(d['count'] for d in list(actual.values()))
expected_count = 0.0 + sum(d['count'] for d in expected.values()) expected_count = 0.0 + sum(d['count'] for d in list(expected.values()))
self.assertGreater(actual_count, 1) self.assertGreater(actual_count, 1)
self.assertGreater(expected_count, 1) self.assertGreater(expected_count, 1)
for k in set(actual.keys() + expected.keys()): for k in set(list(actual.keys()) + list(expected.keys())):
if k not in expected: if k not in expected:
self.fail('Key %s was produced but not expected! %r != %r' % (k, actual, expected)) self.fail('Key %s was produced but not expected! %r != %r' % (k, actual, expected))
expected_probability = expected[k]['count'] / expected_count expected_probability = expected[k]['count'] / expected_count
@ -56,10 +56,10 @@ class TestCopycat(unittest.TestCase):
actual_lo = lower_bound_on_probability(actual[k]['count'], actual_count) actual_lo = lower_bound_on_probability(actual[k]['count'], actual_count)
actual_hi = upper_bound_on_probability(actual[k]['count'], actual_count) actual_hi = upper_bound_on_probability(actual[k]['count'], actual_count)
if not (actual_lo <= expected_probability <= actual_hi): if not (actual_lo <= expected_probability <= actual_hi):
print 'Failed (%s <= %s <= %s)' % (actual_lo, expected_probability, actual_hi) print('Failed (%s <= %s <= %s)' % (actual_lo, expected_probability, actual_hi))
self.fail('Count ("obviousness" metric) seems way off! %r != %r' % (actual, expected)) self.fail('Count ("obviousness" metric) seems way off! %r != %r' % (actual, expected))
if abs(actual[k]['avgtemp'] - expected[k]['avgtemp']) >= 10.0 + (10.0 / actual[k]['count']): if abs(actual[k]['avgtemp'] - expected[k]['avgtemp']) >= 10.0 + (10.0 / actual[k]['count']):
print 'Failed (%s - %s >= %s)' % (actual[k]['avgtemp'], expected[k]['avgtemp'], 10.0 + (10.0 / actual[k]['count'])) print('Failed (%s - %s >= %s)' % (actual[k]['avgtemp'], expected[k]['avgtemp'], 10.0 + (10.0 / actual[k]['count'])))
self.fail('Temperature ("elegance" metric) seems way off! %r != %r' % (actual, expected)) self.fail('Temperature ("elegance" metric) seems way off! %r != %r' % (actual, expected))
else: else:
actual_hi = upper_bound_on_probability(0, actual_count) actual_hi = upper_bound_on_probability(0, actual_count)
@ -68,7 +68,7 @@ class TestCopycat(unittest.TestCase):
def run_testcase(self, initial, modified, target, iterations, expected): def run_testcase(self, initial, modified, target, iterations, expected):
actual = Copycat().run(initial, modified, target, iterations) actual = Copycat().run(initial, modified, target, iterations)
self.assertEqual(sum(a['count'] for a in actual.values()), iterations) self.assertEqual(sum(a['count'] for a in list(actual.values())), iterations)
self.assertProbabilitiesLookRoughlyLike(actual, expected) self.assertProbabilitiesLookRoughlyLike(actual, expected)
def test_simple_cases(self): def test_simple_cases(self):

View File

@ -1,8 +1,8 @@
import formulas from . import formulas
from bond import Bond from .bond import Bond
from correspondence import Correspondence from .correspondence import Correspondence
from letter import Letter from .letter import Letter
from workspaceString import WorkspaceString from .workspaceString import WorkspaceString
def __adjustUnhappiness(values): def __adjustUnhappiness(values):

View File

@ -1,6 +1,6 @@
from description import Description from .description import Description
from formulas import weightedAverage from .formulas import weightedAverage
from workspaceStructure import WorkspaceStructure from .workspaceStructure import WorkspaceStructure
class WorkspaceObject(WorkspaceStructure): class WorkspaceObject(WorkspaceStructure):
@ -109,7 +109,7 @@ class WorkspaceObject(WorkspaceStructure):
if d.descriptionType.fully_active()] if d.descriptionType.fully_active()]
def getPossibleDescriptions(self, descriptionType): def getPossibleDescriptions(self, descriptionType):
from group import Group # gross, TODO FIXME from .group import Group # gross, TODO FIXME
slipnet = self.ctx.slipnet slipnet = self.ctx.slipnet
descriptions = [] descriptions = []
for link in descriptionType.instanceLinks: for link in descriptionType.instanceLinks:

View File

@ -1,5 +1,5 @@
from group import Group from .group import Group
from letter import Letter from .letter import Letter
class WorkspaceString(object): class WorkspaceString(object):

View File

@ -1,4 +1,4 @@
import formulas from . import formulas
class WorkspaceStructure(object): class WorkspaceStructure(object):

3
copycat/curses_main.py → curses_main.py Normal file → Executable file
View File

@ -1,9 +1,10 @@
#!/usr/bin/env python3
import argparse import argparse
import curses import curses
import logging import logging
from copycat import Copycat from copycat import Copycat
from curses_reporter import CursesReporter from copycat.curses_reporter import CursesReporter
if __name__ == '__main__': if __name__ == '__main__':

16
copycat/main.py → main.py Normal file → Executable file
View File

@ -1,17 +1,16 @@
#!/usr/bin/env python3
import argparse import argparse
import logging import logging
from copycat import Copycat, Reporter from copycat import Copycat, Reporter
class SimpleReporter(Reporter): class SimpleReporter(Reporter):
def report_answer(self, answer): def report_answer(self, answer):
print 'Answered %s (time %d, final temperature %.1f)' % ( print('Answered %s (time %d, final temperature %.1f)' % (
answer['answer'], answer['time'], answer['temp'], answer['answer'], answer['time'], answer['temp'],
) ))
def main():
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO, format='%(message)s', filename='./copycat.log', filemode='w') logging.basicConfig(level=logging.INFO, format='%(message)s', filename='./copycat.log', filemode='w')
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -25,5 +24,8 @@ if __name__ == '__main__':
copycat = Copycat(reporter=SimpleReporter(), rng_seed=options.seed) copycat = Copycat(reporter=SimpleReporter(), rng_seed=options.seed)
answers = copycat.run(options.initial, options.modified, options.target, options.iterations) answers = copycat.run(options.initial, options.modified, options.target, options.iterations)
for answer, d in sorted(answers.iteritems(), key=lambda kv: kv[1]['avgtemp']): 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']) print('%s: %d (avg time %.1f, avg temp %.1f)' % (answer, d['count'], d['avgtime'], d['avgtemp']))
if __name__ == '__main__':
main()