Showing posts with label markov. Show all posts
Showing posts with label markov. Show all posts

Wednesday, October 29, 2008

Markov chain code

A follow up to my markov chain posts, here's the code for a generic markov chain in C#:

A markov chain:

/// <summary>
/// Chain implements a markov chain for a type T
/// allows the generation of sequences based on
/// a sample set of T items
/// </summary>
/// <typeparam name="T">the type of elements</typeparam>
public class Chain<T>
{
Link<T> root = new Link<T>(default(T));
int length;

/// <summary>
/// creates a new chain
/// </summary>
/// <param name="input">Sample set</param>
/// <param name="length">window size for sequences</param>
public Chain(IEnumerable<T> input, int length)
{
this.length = length;
root.Process(input, length);
}

/// <summary>
/// generate a new sequence based on the samples first entry
/// </summary>
/// <param name="max">maximum size of result</param>
/// <returns></returns>
public IEnumerable<T> Generate(int max)
{
foreach (Link<T> next in root.Generate(root.SelectRandomLink().Data, length, max))
yield return next.Data;
}

/// <summary>
/// generate a new sequence based on the sample
/// </summary>
/// <param name="start">the item to start with</param>
/// <param name="max">maximum size of result</param>
/// <returns></returns>
public IEnumerable<T> Generate(T start, int max)
{
foreach (Link<T> next in root.Generate(start, length, max))
yield return next.Data;
}
}


consists of links:

/// <summary>
/// parts of a chain (markcov)
/// </summary>
/// <typeparam name="T">link type</typeparam>
internal class Link<T>
{
T data;
int count;
// following links
Dictionary<T, Link<T>> links;

private Link()
{
}

/// <summary>
/// create a new link
/// </summary>
/// <param name="data">value of the item in sequence</param>
internal Link(T data)
{
this.data = data;
this.count = 0;

links = new Dictionary<T, Link<T>>();
}

/// <summary>
/// process the input in window sized chunks
/// </summary>
/// <param name="input">the sample set</param>
/// <param name="length">size of sequence window</param>
public void Process(IEnumerable<T> input, int length)
{
// holds the current window
Queue<T> window = new Queue<T>(length);

// process the input, a window at a time (overlapping)
foreach (T part in input)
{
if (window.Count == length)
window.Dequeue();
window.Enqueue(part);

ProcessWindow(window);
}
}

/// <summary>
/// process the window to construct the chain
/// </summary>
/// <param name="window"></param>
private void ProcessWindow(Queue<T> window)
{
Link<T> link = this;

foreach (T part in window)
link = link.Process(part);
}

/// <summary>
/// process an item following us
/// keep track of how many times
/// we are followed by each item
/// </summary>
/// <param name="part"></param>
/// <returns></returns>
internal Link<T> Process(T part)
{
Link<T> link = Find(part);

// not been followed by this
// item before
if (link == null)
{
link = new Link<T>(part);
links.Add(part, link);
}

link.Seen();

return link;
}

private void Seen()
{
count++;
}

public T Data
{
get
{
return data;
}
}

public int Occurances
{
get
{
return count;
}
}

/// <summary>
/// Total number of incidences after this link
/// </summary>
public int ChildOccurances
{
get
{
// sum all followers occurances
int result = links.Sum(link => link.Value.Occurances);

return result;
}
}

public override string ToString()
{
return String.Format("{0} ({1})", data, count);
}

/// <summary>
/// find a follower of this link
/// </summary>
/// <param name="start">item to be found</param>
/// <returns></returns>
internal Link<T> Find(T follower)
{
Link<T> link = null;

if (links.ContainsKey(follower))
link = links[follower];

return link;
}

static Random rand = new Random();
/// <summary>
/// select a random follower weighted
/// towards followers that followed us
/// more often in the sample set
/// </summary>
/// <returns></returns>
public Link<T> SelectRandomLink()
{
Link<T> link = null;

int universe = this.ChildOccurances;

// select a random probability
int rnd = rand.Next(1, universe+1);

// match the probability by treating
// the followers as bands of probability
int total = 0;
foreach (Link<T> child in links.Values)
{
total += child.Occurances;

if (total >= rnd)
{
link = child;
break;
}
}

return link;
}

/// <summary>
/// find a window of followers that
/// are after this link, returns where
/// the last link if found, or null if
/// this window never occured after this link
/// </summary>
/// <param name="window">the sequence to look for</param>
/// <returns></returns>
private Link<T> Find(Queue<T> window)
{
Link<T> link = this;

foreach (T part in window)
{
link = link.Find(part);

if (link == null)
break;
}

return link;
}

/// <summary>
/// a generated set of followers based
/// on the likelyhood of sequence steps
/// seen in the sample data
/// </summary>
/// <param name="start">a seed value to start the sequence with</param>
/// <param name="length">how bug a window to use for sequence steps</param>
/// <param name="max">maximum size of the set produced</param>
/// <returns></returns>
internal IEnumerable<Link<T>> Generate(T start, int length, int max)
{
var window = new Queue<T>(length);

window.Enqueue(start);

for (Link<T> link = Find(window); link != null && max != 0; link = Find(window), max--)
{
var next = link.SelectRandomLink();

yield return link;

if (window.Count == length-1)
window.Dequeue();
if (next != null)
window.Enqueue(next.Data);
}
}
}


which can be called:

static void Main(string[] args)
{
// sample data set
string seed = Tidy(@"Twinkle, twinkle, little star,
How I wonder what you are!
Up above the world so high,
Like a diamond in the sky!

When the blazing sun is gone,
When he nothing shines upon,
Then you show your little light,
Twinkle, twinkle, all the night.

Then the traveller in the dark,
Thanks you for your tiny spark,
He could not see which way to go,
If you did not twinkle so.

In the dark blue sky you keep,
And often through my curtains peep,
For you never shut your eye,
Till the sun is in the sky.

As your bright and tiny spark,
Lights the traveller in the dark,—
Though I know not what you are,
Twinkle, twinkle, little star.
");

// tokenise the input string
var seedList = new List<string>(Split(seed.ToLower()));
// create a chain with a window size of 4
var chain = new Chain<string>(seedList, 4);

// generate a new sequence using a starting word, and maximum return size
var generated = new List<string>(chain.Generate("twinkle", 2000));
// output the results to the console
generated.ForEach(item => Console.Write("{0}", item));
}

// tokenise a string into words (regex definition of word)
private static IEnumerable<string> Split(string subject)
{
List<string> tokens = new List<string>();
Regex regex = new Regex(@"(\W+)");
tokens.AddRange(regex.Split(subject));

return tokens;
}


Giving output such as:
twinkle, little star,
how i know not twinkle so.

in the sky.

as your tiny spark,
lights the sky!

when the night.

then the traveller in the dark blue sky you never shut your eye,
till the sky.

as your eye,
till the sun is gone,
when he nothing shines upon,
then you are!
up above the dark,
thanks you did not what you are,
twinkle, twinkle, all the sky!


One of the interesting side-effects of tokenizing using a simple regex is that if the input stream is HTML the Markov chain will treat HTML as words as well and therefore not only generate text that looks like the input, but is also formatted like the input - this also works for punctuation.

Wednesday, October 15, 2008

Hamlet vs Twinkle, Brown and Cameron

ok, I've lost the plot - but I realised that this could be generalised into a general Vs engine, so without further ado!

Alternative Hamlet
Hamlet Vs Twinkle, Twinkle little star
Hamlet Vs David Cameron's Party speech
Hamlet Vs Gordon Brown's Global Economy speech
Hamlet Vs Bush
Hamlet Vs Obama
Hamlet Vs McCain

must, stop.. but Cameron version very good:

SCENE I. Elsinore. A million victims from alcohol related-attacks.

Sound money; low taxes – and it is a good child and a fair thought to lie between maids' legs.

HAMLET
How much I’ve worked in business alongside great entrepreneurs. I believe to be all around us.

Danes
[Aside] Though this be so.' We pray you, madam.

HAMLET
I'll set those to you like the herald Mercury
New-lighted on a heaven-kissing hill;
No, by strong hand
Of violent birth, but it’s not just for their care so doctors stop answering to Whitehall, no spirit dares stir abroad;
And let him, Horatio: a certain
convocation of politic worms are e'en with losing his wits.

MARCELLUS
Nay, do not know from personal experience just how brilliant and dedicated the people muddied,
Stood challenger on mount of all parties and none who created these safety nets and springboards. But it’s not my meaning: but I
cannot play upon me.

HAMLET
I am afeard you make it.

HAMLET
Why, what from our brother Norway?

QUEEN GERTRUDE
It is 'Adieu, adieu!
If it will please you go about to speak it profanely,
Look to't that can crop up on your heads: he, repulsed--a short tale to make ourselves relevant to the stage with tears
Had he been put on by a forged process of my cause,
To give the first Conservative metropolitan council in the mind and soul
To both your honours.

Hamlet using a Markov chain

Still playing with Markov chains, created a webpage that generates alternative versions of Hamlet, sample excerpt:


SCENE I. Elsinore. A room in Polonius' house.

Enter KING CLAUDIUS, attended
KING CLAUDIUS and POLONIUS

LORD POLONIUS

[Behind] O, ho! do you mark that?

QUEEN GERTRUDE

As kill a king!

FRANCISCO

Nay, I know not:
Is by a sleep to say we end
The ratifiers and props of every word,
They are not the trail of policy so sure
As hush as death, anon the dreadful thunder
Doth all the days i' the church.

KING CLAUDIUS

Give you good night.

Exit POLONIUS

Will you be honest and fair, your honesty should
admit no discourse to your rest; at night we'll hear a play
Let me be accurst!
None wed the second time I kill my husband dead,
Till the foul crimes done in my life,
That I have found
The observed of all your son's distemper.

QUEEN GERTRUDE

Alas, poor Yorick! I knew him, Horatio: welcome, good Marcellus.

The best poor Yorick so far is "Alas, poor Yorick! I knew your father; " - obviously his dad was not a nice guy ;-)

Tuesday, October 14, 2008

Hamlet vs. Twinkle, twinkle, little star

Give a markov chain a childs rhyme, a dash of Hamlet and behold! Hamlet's little star:


a little ere the mightiest julius fell,
the graves stood tenantless and the suits of solemn black,
nor windy suspiration of forced breath,
no, nor the fruitful river in the sky.

as your bright and tiny spark,
he could not see which way to heaven;
whiles, like a diamond in the roman streets:
as stars with trains of fire and dews of blood,
disasters in the same covenant,
and carriage of the land.

bernardo
i think i hear them. stand, ho! who's there?

enter horatio and marcellus,
the rivals of my watch, bid them make haste.

francisco
i think it was about to speak, when the blazing sun is gone,
when he nothing shines upon,
then you show your little light,
twinkle, twinkle,
all the holy vows of heaven
where now it burns, marcellus and bernardo, on their watch,
in the land,
and why such daily cast of brazen cannon,
and foreign mart for implements of war;
why such impress of shipwrights, whose sore task
does not grow alone
in thews and bulk, but, as this temple waxes,
the inward service of the cock.
some say that ever 'gainst that season comes
wherein our saviour's birth is celebrated,
the bird of dawning singeth all night long:
and then, they say, you spirits oft walk in death.