diff --git a/fibonacci/src/fibonacci/Main.java b/fibonacci/src/fibonacci/Main.java index 33339ca..93c0b5a 100644 --- a/fibonacci/src/fibonacci/Main.java +++ b/fibonacci/src/fibonacci/Main.java @@ -6,11 +6,42 @@ class Examples { ISequence f; ISequence a; + ISequence m; ISeqGen aGen = new AGen(); + ProbTab tab = new ProbTab( + new Cons( + new WordProb( + "never", + new Cons(new ProbPair("gonna", 3), new Mt()) + ), + new Cons( + new WordProb( + "gonna", + new Cons( + new ProbPair("give", 3), + new Mt() + ) + ), + new Cons( + new WordProb( + "give", + new Cons( + new ProbPair("you", 3), + new Mt() + ) + ), + new Mt() + ) + ) + ) + ); + ISeqGen markov = new Markov(tab, "never"); + void init() { this.f = new Fibonacci(); this.a = new GenSeq("", aGen); + this.m = new GenSeq("", markov); } void testFibonacci(Tester t) { @@ -24,6 +55,16 @@ class Examples { t.checkExpect(f.get(), 8); } + void testFibonacciNth(Tester t) { + t.checkExpect(Fibonacci.nth(0), 0); + t.checkExpect(Fibonacci.nth(1), 1); + t.checkExpect(Fibonacci.nth(2), 1); + t.checkExpect(Fibonacci.nth(3), 2); + t.checkExpect(Fibonacci.nth(4), 3); + t.checkExpect(Fibonacci.nth(5), 5); + t.checkExpect(Fibonacci.nth(6), 8); + } + void testASeq(Tester t) { init(); t.checkExpect(a.get(), ""); @@ -33,10 +74,23 @@ class Examples { t.checkExpect(a.get(), "aaaa"); t.checkExpect(a.get(), "aaaaa"); } + + void testMarkov(Tester t) { + init(); + t.checkExpect(m.get(), ""); + t.checkExpect(m.get(), "never"); + t.checkExpect(m.get(), "never gonna"); + t.checkExpect(m.get(), "never gonna give"); + } } // A generic list. interface ILo { + // Find the element that matches the string. + A findMatch(GenMatch match, String a); + // Find the maximum of the list. + A findMax(IntVal intVal); + A findMaxHelper(IntVal intVal, A biggestSoFar, int biggestSoFarVal); } class Cons implements ILo { @@ -48,9 +102,52 @@ class Cons implements ILo { this.first = first; this.rest = rest; } + + public A findMatch(GenMatch match, String s) { + if (match.match(s, this.first)) return this.first; + else return this.rest.findMatch(match, s); + } + + public A findMax(IntVal intVal) { + return this.findMaxHelper(intVal, this.first, intVal.apply(this.first)); + } + + public A findMaxHelper( + IntVal intVal, + A biggestSoFar, + int biggestSoFarVal + ) { + int thisVal = intVal.apply(this.first); + if (thisVal > biggestSoFarVal) return this.rest.findMaxHelper( + intVal, + this.first, + thisVal + ); + else return this.rest.findMaxHelper( + intVal, + biggestSoFar, + biggestSoFarVal + ); + } } class Mt implements ILo { + + public A findMatch(GenMatch match, String s) { + throw new Error("Can't find a match: " + s); + } + + public A findMax(IntVal intVal) { + throw new Error("Can't find max of empty list."); + } + + public A findMaxHelper( + IntVal intVal, + A biggestSoFar, + int biggestSoFarVal + ) { + return biggestSoFar; + } } interface ISequence { @@ -80,14 +177,13 @@ class Fibonacci implements ISequence { public Integer get() { int ret; // What to return. /* - * + * * idx pen pre ret 0 0 1 0 1 0 1 1 2 1 1 2 3 1 2 3 4 2 3 5 5 3 5 8 - * + * */ // F(0) = 0; F(1) = 1 - if (this.idx <= 1) - ret = this.idx; + if (this.idx <= 1) ret = this.idx; else { // F(n) = F(n-1) + F(n-2) ret = this.pre + this.pen; @@ -98,6 +194,10 @@ class Fibonacci implements ISequence { this.idx = this.idx + 1; return ret; } + + static Integer nth(int n) { + return n <= 1 ? n : nth(n - 1) + nth(n - 2); + } } // A generic sequence. @@ -119,10 +219,102 @@ class GenSeq implements ISequence { } } -// A string of n "a"s. +// A string of "a"s. class AGen implements ISeqGen { public String gen(String state) { return state.concat("a"); } } + +// A simple markov chain text generator, with a working memory of 1 word. +class Markov implements ISeqGen { + + ProbTab tab; + String initState; + + Markov(ProbTab tab, String initState) { + this.tab = tab; + this.initState = initState; + } + + public String gen(String state) { + if (state.isEmpty()) return initState; + return state + .concat(" ") + .concat( + this.tab.nextWord(state.substring(state.lastIndexOf(" ") + 1)) + ); + } +} + +// A generic match function. +interface GenMatch { + Boolean match(String s, A a); +} + +class MatchWord implements GenMatch { + + public Boolean match(String word, WordProb prob) { + return prob.word.equals(word); + } +} + +// Get an integer value for a type. +interface IntVal { + int apply(A a); +} + +class ProbPairIntVal implements IntVal { + + public int apply(ProbPair pair) { + return pair.count; + } +} + +// Probability table. +class ProbTab { + + ILo wordProbs; + + ProbTab(ILo wordProbs) { + this.wordProbs = wordProbs; + } + + String nextWord(String state) { + // The completion probabilities for the current state. + WordProb stateCompletions = wordProbs.findMatch(new MatchWord(), state); + String bestWordCompletion = stateCompletions.select(); + return bestWordCompletion; + } +} + +// Word completion probability. +class WordProb { + + String word; + ILo probs; + + WordProb(String word, ILo probs) { + this.word = word; + this.probs = probs; + } + + String select() { + // Ran out of time, but this should really use a weighted random selection. + ProbPair bestFit = this.probs.findMax(new ProbPairIntVal()); + return bestFit.word; + } +} + +// A word and its probability (count). +class ProbPair { + + String word; + int count; + + ProbPair(String word, int count) { + this.word = word; + this.count = count; + } +}