Skip to content

Commit

Permalink
First 'release' build of early class scheme. Added gear ASCII art, mo…
Browse files Browse the repository at this point in the history
…dified .gitignore, fixed tests, refactored markov.py -> poem_engine.py
  • Loading branch information
Alex committed Jun 12, 2018
1 parent 22e3b63 commit e59f067
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
corpus/cmudict/
.idea
src/__pycache__/*
15 changes: 14 additions & 1 deletion ideas/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Directory
# The Information

Here are a few different surveys and introductions to the field of generative poetry that I've found useful.

Expand Down Expand Up @@ -31,4 +31,17 @@ http://interaccess.org/workshop/2017/aug/dust-deep-learning-intro-generative-poe

http://www.sacred-texts.com/cla/plotenn/enn481.htm

*Gears ASCII art from*

https://groups.google.com/forum/#!topic/alt.ascii-art/kgiB6eu0Gy0

_ _
( \_/ )
_ _ __) _ (__
_ _ ( \_/ ) _ (__ (_) __)
( \_/ )__) _ (__( \_/ )) _ (
__) _ ((__ (_) __)) _ ((_/ \_)
(__ (_) __)) _ ((__ (_) __)
) _ ( (_/ \_) ) _ (
(_/ \_) (_/ \_)
1 change: 1 addition & 0 deletions src/corpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def __init__(self, features):
self.n = len(features)
self.features = features


class Sequence():
"""
Represents a sequence of words or feature vectors. Can also be thought of as a sentence. Each sequence is augmented
Expand Down
18 changes: 10 additions & 8 deletions src/corpus_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import unittest
from src.corpus import Corpus
from src.corpus import Sequence
from src.markov import NaiveBayes
from src.poem_engine import NaiveBayes


class TestStringMethods(unittest.TestCase):
Expand All @@ -10,9 +10,9 @@ def test_iter(self):
corpus = Corpus('testcorpus.txt', prefix_padding_size=2)

assert([s.augmented() for s in corpus] == [
['<PRE-2>', '<PRE-1>', 'and', 'all', 'is', 'all', '<END>'],
['<PRE-2>', '<PRE-1>', 'and', 'each', 'is', 'all', '<END>'],
['<PRE-2>', '<PRE-1>', 'and', 'infinite', 'the', 'glory', '<END>']
['~P-2~', '~P-1~', 'and', 'all', 'is', 'all', '~END~'],
['~P-2~', '~P-1~', 'and', 'each', 'is', 'all', '~END~'],
['~P-2~', '~P-1~', 'and', 'infinite', 'the', 'glory', '~END~']
])

assert ([str(s) for s in corpus] == [
Expand All @@ -24,9 +24,9 @@ def test_iter(self):
corpus = Corpus('testcorpus.txt')

assert ([s.augmented() for s in corpus] == [
['and', 'all', 'is', 'all', '<END>'],
['and', 'each', 'is', 'all', '<END>'],
['and', 'infinite', 'the', 'glory', '<END>']
['and', 'all', 'is', 'all', '~END~'],
['and', 'each', 'is', 'all', '~END~'],
['and', 'infinite', 'the', 'glory', '~END~']
])

def test_get(self):
Expand All @@ -42,16 +42,18 @@ def test_slice(self):

self.assertEquals(sequence.list, sequence[0: len(sequence)])


class TestBayes(unittest.TestCase):
def test_p(self):
corpus = Corpus('testcorpus.txt', 3)
bayes = NaiveBayes(3)
bayes.train(corpus)
bayes.turn(corpus)
p = bayes.p(('is',), ('all',))

self.assertEquals(1/3.0, p)

self.assertListEqual(['and', 'all', 'is', 'all'], bayes.generate().list)


if __name__ == '__main__':
unittest.main()
65 changes: 45 additions & 20 deletions src/markov.py → src/poem_engine.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
from collections import Counter
from src.corpus import Corpus, Sequence, END
from abc import ABC, abstractmethod


class PoemEngine():
def train(self, corpus):
class PoemEngine(ABC):

"""
_ _
( \_/ )
_ _ __) _ (__
_ _ ( \_/ ) _ (__ (_) __)
( \_/ )__) _ (__( \_/ )) _ (
__) _ ((__ (_) __)) _ ((_/ \_)
(__ (_) __)) _ ((__ (_) __)
) _ ( (_/ \_) ) _ (
(_/ \_) (_/ \_)
An engine that can crank out poems.
"""

@abstractmethod
def turn(self, corpus):
"""
Crank the engine. Aka, train the engine on the given corpus.
"""
pass

@abstractmethod
def generate(self):
"""
Create something new.
:return:
"""
pass


Expand All @@ -21,6 +47,9 @@ def __init__(self, N):
self.N = N
self.n_grams = []

def turn(self, corpus):
self.n_grams = self.count_ngrams(corpus)

def generate(self):

# Initialize the sequence
Expand All @@ -38,17 +67,6 @@ def generate(self):

return sequence

def prob(self, sequence):
"""
Return the probability of the given sequence.
"""
p = 1.0

for trigram in self.generate_n_grams(sequence, n=3):
p *= p(trigram[2], trigram[:-1])

return p

def p(self, y, x):
"""
p(y|x) according to estimations given by the corpus.
Expand All @@ -60,9 +78,6 @@ def p(self, y, x):

return float(self.n_grams[w][tuple(x) + tuple(y)]) / float(self.n_grams[u][x])

def train(self, corpus):
self.n_grams = self.count_ngrams(corpus)

def count_ngrams(self, corpus):
"""
Make n-grams from a corpus.
Expand Down Expand Up @@ -114,9 +129,19 @@ def print_counts(self):


if __name__ == '__main__':
"""
Example usage.
"""
# Read in the test corpus.
corpus = Corpus('testcorpus.txt', 3)
bayes = NaiveBayes(3)
bayes.train(corpus)
bayes.print_counts()

print(bayes.generate())
# Instantiate a naive bayes engine
engine = NaiveBayes(3)

# Give it a few cranks on the corpus
engine.turn(corpus)
engine.print_counts()

# Generate new text
new_line = engine.generate()
print(new_line)

0 comments on commit e59f067

Please sign in to comment.