tag:blogger.com,1999:blog-33495942754078987362017-06-01T21:53:09.410-07:00A lamb, duh!What do you call a baby eigensheep?Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.comBlogger18125tag:blogger.com,1999:blog-3349594275407898736.post-79260243051363764302012-02-04T13:58:00.000-08:002012-02-04T13:58:50.282-08:00Give 'em the boot...My computing career is rather different from that of a lot of people I know. I haven't been in computing my whole life but, rather, I have two distinct periods of computing -- the first when I was a teen and the second here in my 40s. <br /><br />In the first iteration, I hacked many long hours on my C64, the school's Apple ][e machines and whatever else I could get my hands on. It was a given, at that time, that one spent quite a while basically poking the innards of your machine with a virtual stick. This produced variety of results, most of which were rather boring. But the occasional "spark" of meaningful response what enough fuel to maintain motivation. Luckily none of my sparks actually involved sparks or releasing the magic smoke from the hardware. Perhaps I didn't try hard enough?<br /><br />Now in my second iteration, I have to make things work in a way that supports a family and maintains my interest without completely monopolizing my time. I think this means picking out little projects and experiments that can be done in a weekend afternoon -- things that are interesting, intellectually stimulating and scratch my particular itches. And those itches seem, more and more, to hearken back to the stick poking of the first iteration. Now, since I have to actually get meaningful work done on my machines, and maintain an environment where my family can do things like write school papers and get email, I can't just start poking values into memory and the like. The cost of breaking things is too high. Thankfully, the world is full of virtualization choices....<br /><br />My current interests are bootstrapping, both of languages and computing environments (arguably, very much the same thing). In my undergrad automata class we played with a Universal Turing Machine. This machine behaved, initially, in a way that is very similar to the boot sector of an x86 machine -- it performed a couple of initialization instructions and then jumped over some intervening data to get to the real program to run. The typical DOS-style boot sector does a similar thing -- initializes a few things and then (hand-wavey) jumps into the real program. This realization really struck me and has intrigued me for years. So, the idea is to play with bootstrapping a computing environment from just about nothing. How close to nothing? I think starting at the boot sector is good enough. I suppose I could mess around with writing a BIOS, but that might be too minimal.<br /><br />There's quite a lot of material on bootstrapping your way into various languages, particularly Scheme and Forth. I played with Forth back in the '80s, thought it was pretty cool, but never really learned it. However, it seems ideal for bootstrapping. Apparently, just a few lines of assembler will get enough of a minimal Forth to allow building up a system gradually. So here is a rough sketch of a plan:<br /><br /><br /><ol><li>Build some kind of boot sector code with just enough to allow me to enter machine instructions and then jump to them -- sure to lead to bad results :)</li><li>Use that boot sector to boot a VM and then start hacking. Ideally the next step is to write enough code to allow saving machine state to disk. This will enable me to increment my way to something more useful over multiple sessions. Part of this step is probably rewriting the boot sector to automagically reload the saved machine state -- a basic kernel image.</li><li>Start building up enough environment to get something Forth-like and from there we're off and running!</li></ol><div>I'm not positive how this will play out, and whether I will even actually start it, but it sounds good for now. :)</div>Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-65005263583193314132012-02-04T13:42:00.000-08:002012-02-04T13:42:28.460-08:00Kids...My kids saw me messing around here today and were horrified at the layout I was using. My 12 yr old proceeded to rework it. Hence, the new look... ;)<br /><br />Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-11443947124957382322011-03-08T18:11:00.000-08:002011-03-08T18:21:36.522-08:00Silly little detailsSometimes you have these moments when some silly little detail you've missed for so long suddenly becomes clear and it changes your entire outlook. I just had one of those moments. My friend Harry came to ask me about the State monad. Now, I'm no monadic cowboy, but I've slowly grokked how to use them a little bit.<br /><br />So, we were discussing the structure of return and bind for State, and started to talk about runState. In my attempts to explain it, I realized something silly -- it's an accessor function for the record type State!! Duh! Now it call becomes clear!<br /><br />All along I had assumed that runState was some function floating around in some file somewhere that I just hadn't found yet. But no, it's just the field accessor for the runState field in the State record. No one ever constructs a State instance using that syntax, but they access it that way all the time. It turns out:<br /><br /><code><br />let m = State (\s -> let foo = ... in (foo a, s))<br /></code><br /><br />is synonymous with<br /><br /><code><br />let m = State { runState = (\s -> let ...)}<br /></code><br /><br />so when I do<br /><br /><code><br />let (a,s') = runState m s<br /></code><br /><br />I'm really just getting that function back out of the State record and applying it to s!! <br /><br />Woah. <br /><br />I'm not really sure how I've missed this the whole time. Probably others who read this will wonder how I got this far without figuring it out. But, there it is.<br /><br />Maybe this will help someone. It's sure helped me.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-66557778974371569082010-09-15T13:41:00.000-07:002010-09-15T13:55:49.829-07:00\$100 WordsMy eleven year old daughter came home with a homework problem. The task is to find \$100 words. A \$100 word is a word whose letters, when assigned values, sum to 100. Each one she finds is worth "\$100" in their little game at school. Okay cool! But the values are assigned like this:<br /><br /><ul><br /><li>a = 1</li><br /><li>b = 3</li><br />...<br /><li>m = 25</li><br /><li>n = 26</li><br /><li>o = 24</li><br />...<br /><li>z = 2</li><br /></ul><br /><br />This is not exactly the most intuitive way to number the alphabet, and it certainly makes it hard to evaluate a given word as the typical mapping we're used to (a=1, b=2...) doesn't help. I gave up after a few minutes and told her she should learn to program to solve the problem. <br /><br />She wasn't too thrilled with that idea, but here's my simple Haskell solution:<br /><br /><pre><br />import Char (isUpper)<br /><br />values :: [(Char, Int)]<br />values = zip (interleave ['a'..'m'] ['z','y'..'n']) [1..26]<br /> where<br /> interleave :: [a] -> [a] -> [a]<br /> interleave (x:xs) (y:ys) = x : y : interleave xs ys<br /> interleave _ _ = []<br /><br />charValue :: Char -> Int<br />charValue c = case lookup c values of<br /> Nothing -> 0<br /> Just v -> v<br /><br />wordValue :: String -> Int<br />wordValue = foldl (\s c -> s + charValue c) 0<br /><br />goodWord :: String -> Bool<br />goodWord word@(x:_) = (not $ isUpper x) && wordValue word == 100<br />goodWord [] = False<br /><br />main :: IO ()<br />main = interact (unlines . filter goodWord . lines)<br /></pre><br /><br />Just feed it a list of words, like the handy /etc/dictionaries-common/words and away it goes...<br /><br /><pre><br />$ ./DollarWords < /etc/dictionaries-common/words <br />abductor's<br />abductors<br />abidings<br />...<br /><br />$ ./DollarWords < /etc/dictionaries-common/words | wc -l<br />652<br /></pre><br /><br /><br />So, if I was to unleash this on her poor unsuspecting teachers, her team would rocket ahead with \$652,000! But I guess that wouldn't be fair since she didn't write the program...<br /><br />I'd love to see other versions of solutions for this problem.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com5tag:blogger.com,1999:blog-3349594275407898736.post-1616164213211786862010-09-08T20:07:00.000-07:002010-09-14T13:37:30.637-07:00Decoding Huffman codes without the treeOkay, so, <a href="http://lambduh.blogspot.com/2010/08/serializing-huffman-trees.html">last time</a> I demonstrated how to serialize a Huffman decoding tree into a simple stack-based language for rebuilding the tree. This was pretty interesting in it's own right, in my opinion, but was only a step down the road to the material in this installment... how to decode the Huffman code without the Huffman decoding tree. That is, the intervening data structure, the Huffman decoding tree, is completely eliminated, replacing it with a call graph that does the decoding instead. <br /><br />Like everything so far, a lot is owed to Heinrich Apfelmus' <a href="http://apfelmus.nfshost.com/articles/fun-with-morse-code.html">morse code</a> example, from which this work is directly taken.<br /><br />This technique of removing the intermediate data structure is called <a href="http://en.wikipedia.org/wiki/Deforestation_(computer_science)">deforestation</a>. In this case, when decoding a string of encoded characters, the Huffman decoding tree is built, and then traversed to find a decoded letter. The construction of the tree is a recursive application of the tree constructors starting at the root of the tree. This construction actually happens backards, starting with leaf nodes which are assembled into branch nodes repeatedly until there is only one branch node, the root, left. In a lazy language like Haskell, these nodes may not be evaluated, but instead left as a tree of thunks, unevaluated function calls, where the function calls are calls to the node constructor. Then the decoding is a recursive traversal of that tree looking for a leaf node to decode the letter. <br /><br />The construction of the tree looks essentially like this:<br /><br /><pre><br />(Branch (Branch (Leaf 'a') (Leaf 'b')) (Branch (Leaf 'c') (Branch (Leaf 'd') (Leaf 'e')))<br /></pre><br /><br />(with some stuff left out for clarity).<br /><br />Apfelmus' replaces the constructor calls with functions that tell what to do in the case of reading a particular character from the input stream. And this is where one of the fundamental differences between the morse code tree and the Huffman coding tree come to light. The morse code tree is essentially a <a href="http://en.wikipedia.org/wiki/Trie">trie</a> -- the resulting character returned is based on where you are in the tree when you run out of input (morse code is broken into "words" for each letter). Each node in the morse code tree has a letter associated with it. Each dash or dot moves you further into the tree and to a different letter (allowing, I suppose, a form of partial result, though it has no meaning). When the symbols in a particular morse code "word" are used up, whatever node you're looking at is the character that has been decoded. <br /><br />To implement this, Apfelmus' uses the following, (here I use 1's and 0's instead of dashes and dots):<br /><br /><pre><br />branch c x y = \code -> case code of<br /> '0':ds -> x ds<br /> '1':ds -> y ds<br /> [] -> c<br /><br />leaf = undefined<br /></pre><br /><br />The leaf can be undefined because any well-formed morse code will never reach the leaves of the tree. And if there is no input left, the last case in the branch function, then you're done, emit the character. I won't go into the details of how these functions are used, you can read his post yourself.<br /><br />In the Huffman tree, this is not the case. First, the incoming code is not broken into "words". It is all one stream. Secondly, the decoding happens at the leaf nodes so the leaf function has to actually do something. Finally, in the decoding process, we have to keep track of what hasn't been decoded so far because we'll need it for the next letter.<br /><br />The result looks like this:<br /><br /><pre><br />type Code = String -- an encoded message<br />type Result = (Char, Code)<br /><br />branch :: (Code -> Result) -> (Code -> Result) -> (Code -> Result)<br />branch x y = \code -> case code of<br /> '0':ds -> x ds<br /> '1':ds -> y ds<br /><br /><br />leaf :: Code -> (Code -> Result)<br />leaf [c] = \code -> (c, code)<br /></pre><br /><br />Note here the difference. The branch function never returns a decoded character. That is pushed into the leaf function which also returns the unprocessed remaining portion of the code. <br /><br />Now to put it together. In the last installment we had an interpret function that used HuffTree constructors to build a data structure. In this case, we replace those constructors with our two functions:<br /><br /><pre><br />interpret' :: Program -> Code -> Result<br />interpret' = head . foldl exec []<br /> where<br /> exec (rt:lt:xs) '_' = branch lt rt : xs<br /> exec xs c = leaf [c] : xs<br /></pre><br /><br />Instead of building a data structure, we're building a call graph -- a graph of function calls that trace the decoding of a code into a character and a remaining code (the Result type). Each call to interpret' with a Program and a Code argument produces one decoded letter and the rest like this:<br /><br /><pre><br />*Huffman> let prog = compile $ buildDecTree "hello world"<br />*Huffman> prog<br />"rw_eh__l d_o___"<br />*Huffman> let code = encode "hello world"<br />*Huffman> code<br />"01101010101111100001111000101101"<br />*Huffman> interpret' prog code<br />('h',"01010101111100001111000101101")<br /></pre><br /><br />Subsequent calls to interpret' continue the process<br /><br /><pre><br />*Huffman> interpret' prog (snd it)<br />('e',"10101111100001111000101101")<br />*Huffman> interpret' prog (snd it)<br />('l',"101111100001111000101101")<br /></pre><br /><br />So, to wrap it all up, we recursively build up the decoded message until we've run out of code:<br /><br /><pre><br />decode' :: Program -> Code -> Message<br />decode' prog code = runInterp "" code<br /> where<br /> runInterp :: Message -> Code -> Message<br /> runInterp s [] = s<br /> runInterp s cd = uncurry (\c rest -> runInterp (s++[c]) rest) $ interpret' prog cd<br /></pre><br /><br />And we can see that it works:<br /><br /><pre><br />*Huffman> decode' prog code<br />"hello world"<br /></pre><br /><br />Ta da!<br /><br />Okay, now come the caveats. <br /><br />First, this was begun as an exercise for myself, just to see if I could do it. It was pretty fun, and I'm happy with the results. But, being done just for me (despite my sharing with you) it's probably got all sorts of problems...<br /><br />Second, this type of deforestation, as far as I can tell, is not necessarily a gain. For example, depending on the semantics of the language it's implemented in, you may end up just building a whole pile of thunks on the stack that don't actually do you any good. In other words, it may all be for naught... building the intermediate data structure may be just as good or better, and is certainly more clear and understandable.<br /><br />Third, I really ran through the end here. This is at least partially because I wanted to get done, but also because Apfelmus does an excellent job, much better than I could do, of explaining this. I encourage you to read his post.<br /><br />Comments, suggestions etc are very very welcome. And the code is available in various stages on <a href="http://git.swclan.homelinux.org/huffman.git">my git server</a>.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-73612376438773840292010-08-22T20:50:00.000-07:002010-08-22T21:14:29.312-07:00Serializing Huffman TreesIf you've been following, then you know I'm <a href="http://lambduh.blogspot.com/2010/08/huffman-coding-in-haskell.html">playing</a> with Huffman trees and attempting follow Heinrich Apfelmus' <a href="http://apfelmus.nfshost.com/articles/fun-with-morse-code.html">morse code example</a>.<br /><br />Previously, I built a Huffman Tree data type and some functions for encoding and decoding messages using that structure. This installment is rather short, covering a way to serialize and deserialize a HuffTree structure. This serves two purposes. First, it's a way to encode the Huffman tree so that the recipient of a message can decode it. I make no claims as to its efficiency or anything like that. It works, and is really more of an exercise for myself. The second reason is in my pursuit of mimicking Apfelmus' work, I want to effectively obscure the Huffman tree structure, making it more or less vanish into the call structure.<br /><br /><h3>Compiling a HuffTree and Interpreting the Code</h3><br /><br />The technique here is pretty straightforward. We will traverse the tree, using a post-order traversal, generating a code to be later used for rebuilding the tree. The code is interpreted as a stack based language. In the language, any symbol, other than '_' (underscore) encodes a push operation of that character onto the stack. An underscore means pop two items off the stack, create a Branch node with them and push the new node onto the stack. As these operations are repeated, assuming a well-formed code, the result will be one node left on the stack containing the reconstructed tree. <br /><br />Both functions are very simple:<br /><br /><pre><br />-- here we emit an "_" to signal a branch. This "_" will be used to do <br />-- a pop/merge/push when we interpret the code later <br />compile :: HuffTree -> String<br />compile (Leaf sy _) = [sy]<br />compile (Branch _ lt rt) = compile lt ++ compile rt ++ "_"<br /><br /><br />interpret :: [Char] -> HuffTree<br />interpret = head . foldl exec []<br /> where<br /> exec :: [HuffTree] -> Char -> [HuffTree]<br /> exec (rt:lt:xs) '_' = (Branch 0 lt rt) : xs<br /> exec xs c = (Leaf c 0) : xs<br /><br /></pre><br /><br />For compiling, simple pattern matching in a recursive tree traversal does the trick. For interpreting, a foldl with a constructor function is all that's needed. Note that the interpret function is stolen almost directly from Apfelmus' work, except that the Branch and Leaf operations are swapped.<br /><br />These functions work just fine: <br /><br /><pre><br />*Huffman> let tree = buildDecTree "hello world"<br />*Huffman> tree<br />Branch<br /> Branch<br /> Branch<br /> Leaf r<br /> Leaf w<br /> Branch<br /> Leaf e<br /> Leaf h<br /> Branch<br /> Leaf l<br /> Branch<br /> Branch<br /> Leaf<br /> Leaf d<br /> Leaf o<br /><br />*Huffman> compile tree<br />"rw_eh__l d_o___"<br />*Huffman> interpret "rw_eh__l d_o___"<br />Branch<br /> Branch<br /> Branch<br /> Leaf r<br /> Leaf w<br /> Branch<br /> Leaf e<br /> Leaf h<br /> Branch<br /> Leaf l<br /> Branch<br /> Branch<br /> Leaf<br /> Leaf d<br /> Leaf o<br /><br /></pre><br /><br />In this compile-interpret sequence, one thing is lost -- the weight of the nodes. This is acceptable because the weights are only used for building the initial tree based upon the character frequencies of the encoded message. Once that step is done, the weights are simply unnecessary. <br /><br />It would be nice to be able to compare trees for equality, if for no other purpose than to get the machine to tell us that interpret and compile are inverses (modulo the weights). So our HuffTree type needs to be an instance of Eq with an (==) function that is meaningful for our purposes. In this case we want structural equality with the values in the leaf nodes being compared directly. Weights are ignored.<br /><br /><pre><br />instance Eq HuffTree where<br /> (==) (Branch _ l1 r1) (Branch _ l2 r2) = l1 == l2 && r1 == r2<br /> (==) (Leaf s1 _) (Leaf s2 _) = s1 == s2<br /> (==) _ _ = False<br /></pre><br /><br />The goal here is trees that are equal should encode and decode in the same way. So the shape of the tree is important. That's what this equality function does.<br /><br /><pre><br />*Huffman> buildDecTree "hello world" == (interpret . compile $ buildDecTree "hello world")<br />True<br />*Huffman> buildDecTree "hello world" == (interpret . compile $ buildDecTree $ reverse "hello world")<br />True<br /></pre><br /><br />And we can see that this works. Even for the reversed message, because the tree built from this message has the same structure.<br /><br />That's it for this installment -- a short one. Next time I'll start messing with the deforestation/fusion stuff.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-40262643998003265132010-08-17T10:54:00.002-07:002010-08-17T13:53:57.247-07:00Huffman Coding in HaskellTo follow up on my <a href="http://lambduh.blogspot.com/2010/08/haskell-approach-to-huffman-coding.html">post</a> from last week, here is the beginnings of some fun with Huffman Coding in Haskell. Remember that this was spurred by Heinrich Apfelmus' <a href="http://apfelmus.nfshost.com/articles/fun-with-morse-code.html">article</a> using fusion and other fun things with Morse Code.<br /><br /><h3>Huffman Coding</h3><br />There is nothing revolutionary in here, just a reasonably straight-up Huffman coding algorithm that converts a message into a string of 1's and 0's and then can convert them back to the original message. I borrowed heavily from <a href="http://coder.bsimmons.name/blog/2009/05/huffman-coding/">this</a> blog posting and if you look at the history of my <a href="http://git.swclan.homelinux.org/huffman.git">source code</a> you'll see that it was a HUGE help! The code snippets below are just that, snippets. Look to the complete <a href="http://git.swclan.homelinux.org/huffman.git">source code</a> to get a working example.<br /><br />Anyway, the basics are as follows.... Given a message, we count the frequency of each character and build up a dictionary of characters and their respective frequencies.<br /><br /><pre><br />-- the list of character<br />frequencies<br />type FreqList = [(Char, Int)]<br /><br />-- function to count character frequency, storing the results in a map.<br />charFreq :: String -> FreqList<br />charFreq s = Data.Map.toList $ foldl charFreq' Data.Map.empty s<br /><br />charFreq' :: Map Char Int -> Char -> Map Char Int<br />charFreq' m c = Data.Map.insertWith (+) c 1 m<br /></pre><br /><br />These frequencies are later used as weights for building the Huffman Tree. A Huffman tree is a binary tree built so that higher frequency characters are more shallow leaves and lower frequency characters are deeper leaves. This means that high frequency characters are represented with fewer bits than low frequency characters. This gives an overall shorter stream of bits for encoding the message.<br /><br />So, we need a data type to represent the Huffman Tree:<br /><br /><pre><br />-- data structure for huffman trees <br />data HuffTree = Branch { wt :: Int, l :: HuffTree, r :: HuffTree }<br /> | Leaf { symbol :: Char, wt :: Int }<br /> deriving (Eq)<br /><br />instance Ord HuffTree where<br /> compare = compare `on` wt<br /><br />mappend :: HuffTree -> HuffTree -> HuffTree<br />mappend x y = Branch (wt x + wt y) x y<br /></pre><br /><br />We've made HuffTree an instance of Ord so that it can be sorted on its wt (weight) field. This is useful for building the tree -- we can keep the nodes in the order we want easily. And the function mappend is handy for "adding" HuffTrees together.<br /><br />The process for building a Huffman Tree from a list of characters and weights is pretty straightforward. We create a list of HuffTrees, using just Leaf constructors and storing their weights. This list is sorted by weight so that the Leaf nodes that represent the characters with the lowest frequency or weight are first. These HuffTree elements are pulled off the list, combined with the `mappend` function and then sorted back into the list. This process continues until there is only one HuffTree left in the list. This is the Huffman coding tree for our message.<br /><br /><pre><br />-- produce a decoding tree from a string <br />buildDecTree :: String -> HuffTree<br />buildDecTree = build . sort . map (uncurry Leaf) . charFreq<br /> where<br /> build :: [ HuffTree ] -> HuffTree<br /> build [] = error "Empty Leaf list"<br /> build (t:[]) = t<br /> build (x:y:ts) = build $ Data.List.insert (mappend x y) ts<br /></pre><br /><br />As usual, Haskell make this sort of operation ridiculously simple and intuitive.<br /><br />with an instance of Show for HuffTree, we can see the results:<br /><br /><pre><br />*Huffman> buildDecTree "hello world"<br />Branch 11<br /> Branch 4<br /> Branch 2<br /> Leaf r 1<br /> Leaf w 1<br /> Branch 2<br /> Leaf e 1<br /> Leaf h 1<br /> Branch 7<br /> Leaf l 3<br /> Branch 4<br /> Branch 2<br /> Leaf 1<br /> Leaf d 1<br /> Leaf o 2<br /></pre><br /><br />To encode a character using the generated tree, we record the path taken to get to the character emitting a "0" for left branches taken and a "1" for right branches. In the above tree, where the first branch listed is the left branch, the path to the letter "e" is left -> right -> left. Thus the code for "e" is "010", only three bits to represent an 8-bit character. To encode an entire message, we repeat the process for each letter. But traversing the tree for each letter is neither efficient nor elegant. So we flatten the tree into a dictionary of characters mapped to their encodings. To do this, we traverse the tree once, recursively recording and emitting dictionary entries.<br /><br /><pre><br />-- produce an encoding dictionary from the decoding tree <br />buildEncDict :: HuffTree -> [(Char, String)]<br />buildEncDict = buildEncDict' ""<br /><br />buildEncDict' :: String -> HuffTree -> [(Char, String)]<br />buildEncDict' s (Leaf sy _) = [(sy,s)]<br />buildEncDict' s (Branch _ lt rt) = buildEncDict' (s ++ "0") lt<br /> ++ buildEncDict' (s ++ "1") rt<br /></pre><br /><br />Now to encode a character, we simply to a lookup in the dictionary. In this case, it's just a list of character-code pairs but it could easily be, for a larger character set, a search tree keyed by the character storing code values. As an aside, this would be an interesting exercise, to traverse the Huffman tree transforming it into a binary search tree. Regardless, encoding is very straightforward:<br /><br /><pre><br />-- here is an encoding function to turn a String into a Code <br />encode :: String -> Code<br />encode s = encode' (buildEncDict $ buildDecTree s) s<br /><br />encode' :: [(Char, String)] -> String -> Code<br />encode' _ [] = []<br />encode' d (s:ss) = (fromJust $ Prelude.lookup s d) ++ encode' d ss<br /></pre><br /><br />And finally, to decode a message, you traverse the HuffmanTree directly, turning 0's into left branches and 1's into right branches in the tree traversal. When the traversal reaches a Leaf node, then a character has been decoded.<br /><br /><pre><br />-- and a decode function to turn a code and a tree into a string <br />decode :: HuffTree -> Code -> String<br />decode t code = decode' t code<br /> where<br /> decode' (Branch _ lt rt) (c:cs) =<br /> case c of<br /> '0' -> decode' lt cs<br /> '1' -> decode' rt cs<br /> _ -> [] -- "otherwise" produces a warning about unused variable <br /> decode' (Leaf s _) cs = s : decode' t cs -- we need the whole tree again <br /> decode' _ [] = []<br /></pre><br /><br />Note the use of a helper function because to decode each letter, you have to start from the root of the tree. There are likely better ways to do this...<br /><br />That's the basics of Huffman coding in Haskell, and it works just fine:<br /><br /><pre><br />*Huffman> let tree = buildDecTree "hello world"<br />*Huffman> encode "hello world"<br />"01101010101111100001111000101101"<br />*Huffman> decode tree $ encode "hello world"<br />"hello world"<br /></pre><br /><br />But there is a problem. To decode the message, you need the coding tree for that message. I'm sure there are a variety of techniques to transmit the tree as part of the message. One of the things Apfelmus did that intrigued me was develop a stack based language and interpreter to represent the morse code tree as a string of characters. I think this would make a fine way to encode the tree into the front of the message. We should be able to extract a string of characters from the Huffman tree for a particular message and use that string of characters to reconstruct the tree on the other side. Now this will add some significant overhead to the output for a given message, but I'm not necessarily concerned with space efficiency here as much as learning about these kinds of transformations.<br /><br /><h3>Observations</h3><br />I <a href="http://lambduh.blogspot.com/2010/08/haskell-approach-to-huffman-coding.html">previously</a> mentioned some differences between Apfelmus' implementation of the morse code decoder and a similar Huffman decoder. Having gone through the process of building this code, I"ve come to better recognize those differences. <br /><br />First, as I mentioned before, in the Huffman tree, the leaves are important and the result is an encoding of the routes through the tree to obtain the desired characters. We use the Leaf nodes to know when a particular character has been decoded because the code is an undelineated string of bits. In the morse code solution, the "letters" are delineated. It is clear when a particular letter is complete. So the decoding works slightly differently and the tree is really a trie, where the result is whatever character you land on when the input stream for a particular character ends. I'm not sure what the implications will be for the application of the fusion technique, but we'll see.<br /><br />When decoding, you don't strictly need the weights anymore, they are only used to build the tree. So transmitting the decoding tree is simpler than it seems at first glance. Again we'll see what comes of that as I progress through this. <br /><br />Next installment should be a "compiler" to turn a HuffTree into a string of characters that can be used to reconstruct the tree again using an "interpreter". Should be fun!Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com2tag:blogger.com,1999:blog-3349594275407898736.post-85880579164574145782010-08-08T13:55:00.000-07:002010-08-17T13:55:14.503-07:00A Haskell approach to Huffman CodingI just ran across <a href="http://apfelmus.nfshost.com/about.html">Heinrich Apfelmus'</a> discussion of <a href="http://apfelmus.nfshost.com/articles/fun-with-morse-code.html">morse code</a> and I think it's pretty cool. I like the progression from a straightforward initial approach to a very clever result. I was really struck by the similarities of parsing morse code with a tree and <a href="http://en.wikipedia.org/wiki/Huffman_coding">Huffman Coding</a>. My goal this week is to try to apply Apfelmus' technique to Huffman coding. <br /><br />There are some important distinctions between the morse code tree and Huffman Coding. First, in Huffman coding, the leaves are important. The symbols are stored in the leaves of the tree instead of in the nodes as in the morse code solution. Additionally, the Huffman tree structure itself encodes the frequency of the symbols in the source, a consideration that is not required in the morse code. This changes the interpreter required for constructing the tree. Also, the Huffman coding tree <span style="font-style:italic;">should</span> be constructed specifically for the data set it is being used to encode. For a reasonably consistent data set, like large amounts of English text, the frequency of symbols for the language in general can certainly be used with reasonable results. But, for encoding other kinds of data, ideally the source should be used to generate frequencies of symbols unique to that source. I'm probably going to ignore this and just use some reasonable standard frequencies instead.<br /><br />So, that's my plan for the week, we'll see how it goes.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-14917804279765600602010-03-22T17:39:00.000-07:002010-03-26T08:06:23.335-07:00You know you're a geek when...You know you're a geek when you catch yourself trying to explain to your 12 year old kid how the pig-latin transformation is not an isomorphism, but is a function (at least it seems so at first glance). And then things diverge into whether one is discussing typographical or aural pig-latin.<br /><br />The anecdotal evidence is pretty clear: the English word "pay" becomes "ay-pay" while the English word "ape" becomes "ape-ay"*. Typographically they are quite distinct, but aurally they can be quite similar, even identical, depending on one's speech patterns. So, spoken pig-latin is not an isomorphism, relying on contextual clues to allow easy translation. But typographical pig-latin should be very straightforward, mechanical, to translate. I'm not even going to go into the occasional pig-latinized French that we have to bust out around here when the kids are eavesdropping.<br /><br />Anyway, that's just a little food for thought ;)<br /><br /><br />* remember that words which begin with a vowel sound merely have the "ay" syllable appended to it.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-42467175809558917632010-01-30T11:54:00.001-08:002010-01-30T12:05:39.977-08:00Grad School! and other stuffI've been letting this languish for a variety of reasons, not the least because I'm just really busy. Carrying 18 credits at school while trying to prep a house for sale is not for the faint-of-heart. So, here is a bit of an update one what I'm not quite getting accomplished.<br /><br />Grad School -- I just got my first grad school acceptance letter. That makes it official that I'm headed to grad school in the fall. Yay! But at the same time that makes everything else much more critical.<br /><br />House, Business -- I'm trying to sell my businesses and our house. Both of these are fairly huge tasks in their own right. I've got some interest in the bar that may pan out to some kind of sale soon, but who knows. The house is an effort in trash hauling, mostly. It's mazing how much crap can accumulate in 10 years! We've got to get about 2/3 of our stuff *out* of the house to make it look acceptable for someone to buy. Then we have to somehow *live* without 2/3 of our stuff. Luckily, about half that 2/3's is probably trash of some kind or another. Can you imagine? 1/3 of our stuff is essentially trash! This is going to be good for us in the long run.<br /><br />School -- I'm carrying a big load at the moment (and next quarter too) in order to get done this spring. It's going to work out, but it's a *lot* of work. Thankfully, some of it's fun. My Senior Project is a great little research project examining the latency of a video system in Linux using <a href="http://www.gstreamer.net/">gStreamer</a> and a real-time kernel. Pretty cool. <br /><br />Side stuff -- the reading list gets longer all the time, especially with impending grad school admission. I've got to catch up on important stuff I feel I'm missing from my undergrad education. Specifically, I want to read up on programming language semantics, compiler design, and play around with some OS stuff. I may have to write the typical crappy little OS project that never gets beyond the bootloader. The projection pursuit project is actually pretty much done. I have one little problem to fix and I can call it a finished prototype, but I'm not sure when I'll get to that. <br /><br />So, that's the update for now. Cheers everyone!Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-11807911871313124422009-09-30T21:26:00.000-07:002009-09-30T22:23:17.246-07:00Projection Pursuit in Haskell, pt 3<span style="font-weight:bold;">Breakthrough.</span><br /><br />Sometimes problem solving requires just a lot of thought. And I don't mean brute force thought, but the gentle, patient thought that comes from relaxing about a problem and just letting your brain work on it for a while. I find I come up with some of my best ideas in the shower. Yeah, I know... But, when something has really been bothering me -- remaining unsolved despite my best efforts -- the solutions typically come at night. Something wakes me up and then I'm up and my mind won't stop and then the solution comes.<br /><br />Such it was last night. I haven't had a lot of time to put into this effort lately, and what effort I've made has been frustrating. If you look at the original <a href="http://swclan.homelinux.org/code/ppursuit/ppursuit.m">Octave source code</a> you'll see that there are a <span style="font-weight:bold;">lot</span> of parameters controlling the algorithm. We've got the raw data itself, the size of the gradient probe, the proportion of the gradient to use, the number of iterations. It's a lot of stuff to cart around. But, I'll get to that in a moment. <br /><br />First, I had spent a lot of time writing some matrix and vector operators. This was a good exercise, though I've ultimately thrown all that code out. One crucial part of this algorithm is the use of the right singular vectors from the singular value decomposition. I certainly didn't want to write an svd function for this exercise. Google to the rescue! I found <a href="http://www.hmatrix.googlepages.com/">hmatrix</a>, and a solution to all my matrix handling problems. So, using hmatrix caused me to dig back through the bits of code I'd already written. At the core of the projection pursuit algorithm is the calculation of the gradient. This solution uses an estimation of the gradient by probing in all dimensions and measuring the change in the kurtosis.<br /><br />So, let's define some helper functions:<br /><br /><pre>{-- calculate modified kurtosis --}<br />kurtosis :: Vector Double -> Double<br />kurtosis y = mean(y) ** 4 - 3<br /><br />{-- calculate the mean of a vector --}<br />mean :: Vector Double -> Double<br />mean y = go 0 0 $ toList y<br /> where<br /> go :: Double -> Int -> [Double] -> Double<br /> go s l [] = s / fromIntegral l<br /> go s l (x:xs) = go (s+x) (l+1) xs<br /><br /><br />{- create a list of vectors to probe h distance in all directions -}<br />hs :: Double -> Int -> [Vector Double]<br />hs h r = toRows . diag . fromList . take r $ repeat h<br /><br /></pre><br /><br />Using these, we can calculate the estimated gradient:<br /><br /><pre>{-- calculate the gradient of a function given a bunch of starting information <br /> f - the function to compute gradient of <br /> h - the probe distance... the smaller the better <br /> z - the raw data set needed for future projections <br /> w - a starting vector/point at which to calculate the gradient --}<br /><br />gradient :: (Vector Double -> Double) -> Double -> Matrix Double -> Vector Double -> Vector Double<br />gradient f h z w = probe ws<br /> where<br /> ws = map ((+) w) . hs h $ rows z<br /> k = f $ w <> z<br /><br /> probe :: [Vector Double] -> Vector Double<br /> probe = fromList . probe'<br /><br /> probe' :: [Vector Double] -> [Double]<br /> probe' [] = []<br /> probe' (x:xs) = (deltaK x) / h : (probe' $ xs)<br /><br /> deltaK :: Vector Double -> Double<br /> deltaK x = k - f (x <> z)<br /></pre><br /><br />This is really pretty straightforward. We calculate a starting kurtosis value, generate a bunch a vectors that shift h-amount in all dimensions, calculate the kurtosis for each of those and concatenate them into a new vector for the gradient. <br /><br />The real breakthrough for me came when I was struggling with how <span style="font-weight:bold;">ugly</span> it was going to be to pass around all this junk. Just ugly and I can't stand it. So last night, while I was lying awake fretting about this, it finally hit me. I don't have to pass around all this stuff. I can just partially apply the gradient function to all the algorithm control parameters, and the raw data, and then just pass that around. So at some point I'll do this:<br /><br /><pre><br />{-- build a gradient function for *this* problem --}<br />grad :: Vector Double -> Vector Double<br />grad = gradient kurtosis h z<br /></pre><br /><br />Now I can just pass around grad and it will carry around all the baggage for me. I know. This is a really simple part of haskell, and it's something that is done all the time. I've certainly done it many times. But for some reason it eluded me for a really long time. The real problem was one of not thinking about this function properly. Yes, all that data is needed to calculate the gradient. But I am <span style="font-weight:bold;">not</span> calculating the gradient of all of this stuff as variables. The function, the raw data and the h distance are all fixed points within the context of the problem. That is, there is only one true variable in this application of the gradient function and that is the current position, w. All along I had been thinking about h and f and z as variables and thus I <span style="font-weight:bold;">had</span> to keep passing them around. And they are variables, within the context of the whole algorithm, but at the level of the gradient, they aren't. Huh. It took me along time to bend my brain around to seeing this the right way.<br /><br />Anyway, there it is. Now that school is back in, I get stolen moments on the bus to work on this, so hopefully the rest will come soon.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-55483409908249247342009-09-30T18:17:00.000-07:002009-09-30T20:11:50.759-07:00The Summer of ChaosSo, time to reminisce about the summer just past. Wow! It's amazing how life throws you curve balls.<br /><br /><span style="font-weight:bold;">The Plan.</span> Heading out of last spring, I was anticipating a summer of general-ed requirements to speed me on my way towards graduation, a little programming work on the side, research on grad-school programs and lots of time for personal projects to be posted here. This was to go alongside taking care of my three daughters and generally being "summery." Cool. Good plan. A little ambitious, but doable.<br /><br /><span style="font-weight:bold;">The Reality.</span> <a href="http://www.farwestbilliards.com/">Business</a> took a nose-dive. So much so that I had to go back behind the bar for the summer to keep things afloat. We pared down to a skeleton staff with me working 4 shifts a week slinging beers. That's just what needed doing.<br /><br />Meanwhile, I did get some side work, technically an internship, though I'm not bothering to take the educational credit, just the CV listing. I spent some time learning Python, flexing my Debian admin skills and playing around with <a href="http://livinglab.cslabs.ewu.edu/">EWU's Living Laboratory</a> project under <a href="http://foo.ewu.edu/">Dr. Jeff</a> <a href="http://jefu.blogspot.com/">Putnam</a>. It was a fun project. I got pretty comfortable with Python, the basics of Postgresql, and Django. Also, I got to play with specifying and implementing the simplest of Domain Specific Languages to allow <a href="http://livinglab.cslabs.ewu.edu/trac/livinglab/wiki/UserCodeDSL">user-entered code</a> to run on our server. That project is ongoing, though I've got precious little time for it now that school is back in. Hopefully, I'll get to extend (or create anew) that language for specifying graphs as well.<br /><br />So, personal projects, grad-school research? All by the wayside. My plans to port my Projection Pursuit algorithm to Haskell got pushed back. A *ton* of reading (Computational Category Theory, A Transition to Advanced Mathematics, Goedel, Escher, Bach, etc.) postponed indefinitely. Grad school selection is only getting started now, and that is such a daunting task! Dr. Putnam suggests I find blogs I like, follow all of their blog links and assemble this graph of blogs and schools and then run a clustering algorithm looking for commonality and hope that helps me narrow down the choices. Hah! That would probably work really well, but given the time available, would take until long past the application deadlines. Plus, I have to prep for the GRE's in a week! Wah!<br /><br /><span style="font-weight:bold;">The Results.</span> Well, what can I say? It is what it is, and I keep marching ahead. Things never go quite the way you expect, but in the end, they work out. I think. I'm getting that Projection Pursuit done. I'm keeping up with my studies. I'm gradually narrowing down the choices for grad-school applications. And somehow I'm still enjoying my family <span style="font-weight:bold;">and</span> keeping food on the table. Not bad :-)Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-10816662511702549492009-08-22T12:30:00.000-07:002009-09-03T08:12:33.404-07:00Projection Pursuit in Haskell, pt 2In this installment, I'll review my original projection pursuit algorithm in Octave and provide some pretty pictures and sounds :)<br /><span style="font-weight:bold;">The Code</span><br />First, you can download <a href="http://swclan.homelinux.org/code/ppursuit/ppursuit.m">the code</a> and follow along if you like.<br /><br />The function accepts a number of parameters to control the gradient probing and stopping criteria, as well as provide the mixed signals. The mixed signals are represented as a row-wise matrix with each row representing a particular mix. Here is the breakdown from the help section of the function:<br /><pre>function [y, K] = ppursuit(h, eta, tol, mxi, x)<br />%<br />% [y, K] = ppursuit(h, eta, tol, mxi, x)<br />%<br />% Projection Pursuit (probing to estimate gradient).<br />% This function uses projection pursuit to demix m<br />% signal mixtures into m estimated source signals.<br />%<br />% h Step size for probing the Kurtosis (K) of the<br />% demixed signals, relative to the magnitude<br />% of the current demixing vector. IOW, K is<br />% probed by looking at K(w + h) in the m<br />% dimensions of w, one at a time. It should be<br />% noted that w is a unit vector, so there is<br />% no need to scale the step size by the current<br />% size of w.<br />% eta Distance that demixing vector w is adjusted<br />% in the direction of the estimated gradient of<br />% K. IOW, wnext = w + eta*g where g is the<br />% estimated gradient of K, normalized to 1.<br />% tol Stopping criterion for gradient ascent. The<br />% ascent terminates when the relative change in<br />% K is < tol. (Change in K divided by K).<br />% mxi Maximum iterations to execute on the ascent<br />% of K for each recovered signal.<br />% x (m x n) matrix of signal mixtures. Each row<br />% is a 1 x n mixture of m source signals. The<br />% source signals may be anything, and there is<br />% no assumed relationship between the n samples<br />% of a given mixture. They may be temporal or<br />% spatial samples.<br />% y The (m x n) source estimates<br />% K The (m x ?) history of the ascent of Kurtosis<br />% for each recovered source. Having this history<br />% allows the caller to tune the search parameters.<br />%</pre><br />The algorithm itself is very straightforward.<br /><ul><br /><li>First, we find the PCA (Principal Component Analysis) to minimize de-mixing errors. Because our two original sound sources are independent, they are uncorrelated. Casting our data into an uncorrelated basis (which is what PCA does) we can easily extract signals as we find them without interfering with the remaining signals. If we did not do this, then we would have to find all the signals simultaneously (by a different technique) so that we could solve the "parallelogram" that they would make (obviously, I'm leaving things out...). So, we do this by taking the SVD (Singular Value Decomposition) of the mix matrix and throwing away "U" and "S". What remains is the mixes represented in an ortho-normal basis (this is a fairly trivial derivation).</li><br /><li>Now we iterate for each row in the mixes:<br /><ul><br /><li>Whiten the mixes by setting the variance to 1</li><br /><li>Select a starting vector for demixing. In the original project, we used a random unit-length vector. I've changed that to a standard basis vector, i, for illustrative purposes.</li><br /><li>Project the mixes onto the trial demixing vector and measure the kurtosis</li><br /><li>Iterate until our stopping criteria are met: that is, we reach the maximum number of iterations, or the change in kurtosis from one iteration to the next fall below our threshold<br /><ul><br /><li>Probe the gradient in each direction, measuring the kurtosis</li><br /><li>Assemble the results of the probe into a gradient vector</li><br /><li>Adjust the trial demixing vector one increment (eta) in the direction of the gradient vector. By moving a fraction of the gradient, we minimize the risk of overshooting the peak of the kurtosis. If we moved by the full gradient, a localized spike in the gradient could easily cause a large displacement of the demixing vector.</li><br /></ul></li><br /><li>At this point, the demixing vector now points in the direction of maximum kurtosis. We project our mixes onto this vector and store the results as the first unmixed signal</li><br /><li>Subtract the unmixed signal from the original mixes to allow further demixing</li><br /></ul></li><br /></ul><br />Please note that I used a stripped down kurtosis calculation which ignores the denominator of the typical calculation. We can do this because the mixes have been whitened so the variance (and thus the denominator of the kurtosis calculation) will be 1.<br /><span style="font-weight:bold;">Results</span><br />So, to test this we need a mixed sound signal like <a href="http://swclan.homelinux.org/code/ppursuit/mix.wav">this</a> mix of a bird chirping and a gong ringing. This sound clip only plays one "mix" of which we have two in <a href="http://swclan.homelinux.org/code/ppursuit/mix.mat">this file</a>. It's a horrific sound... <br /><br />After projecting the mixes into an ortho-normal basis, we can plot the two mixes against each other like this:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_q4vdH9mlCeg/SprSz-dGziI/AAAAAAAAACg/tIH-gLo6-SU/s1600-h/datapoints.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 144px;" src="http://2.bp.blogspot.com/_q4vdH9mlCeg/SprSz-dGziI/AAAAAAAAACg/tIH-gLo6-SU/s200/datapoints.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5375840895600348706" /></a><br /><br />It's pretty clear that there are two distinct signals here, one fairly well defined in a sort of "north-by-north-east" orientation, and another in a "north-west" orientation. I've only plotted about 1 in 5 samples here, otherwise the image just becomes a big blob.<br /><br />After the first iteration of the algorithm, finding the first signal, we can see its progress here:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_q4vdH9mlCeg/SprTz9tAF6I/AAAAAAAAACo/czi1TpNjOko/s1600-h/first_signal.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 144px;" src="http://4.bp.blogspot.com/_q4vdH9mlCeg/SprTz9tAF6I/AAAAAAAAACo/czi1TpNjOko/s200/first_signal.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5375841994910209954" /></a><br />In this image, the red line represents the starting point, the green lines represent the intermediate trial demixing vectors and the blue line is the final vector for the current signal. Notice how the trial demixing vectors probe quickly at first and slow down as we approach the peak of the kurtosis curve and the gradient begins to flatten.<br /><br />This first iteration extracts a pretty clean <a href="http://swclan.homelinux.org/code/ppursuit/bird.wav">bird chirp</a> signal, although if you listen closely, you can hear just a touch of the gong as well.<br /><br />In the second iteration, we can see the algorithm finding the second, more diffuse, signal:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_q4vdH9mlCeg/SprVBmkRC2I/AAAAAAAAACw/_zpAnmEb3hc/s1600-h/second_signal.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 144px;" src="http://4.bp.blogspot.com/_q4vdH9mlCeg/SprVBmkRC2I/AAAAAAAAACw/_zpAnmEb3hc/s200/second_signal.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5375843328729353058" /></a><br /><br />Again, you can see the initially quick probing that slows as we approach the peak of kurtosis. What is not shown here is that the mixes have had the first signal removed. Because there are only two signals here, removing the first signal will project the remaining signal onto a vector, making the extraction of the second signal trivial. But it's still fun to watch it work. The second signal extacted is a rather awful <a href="http://swclan.homelinux.org/code/ppursuit/gong.wav">gong sound</a>. Again, you can still hear just a touch of the bird chirping in the background.<br /><br />Here is the kurtosis history of each probe, using ppursuit(.001, .01, .00001, 2000, mix) as the function call.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_q4vdH9mlCeg/SprZtjHvYXI/AAAAAAAAAC4/oeu64R9UZag/s1600-h/kurtosis_curve.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 144px;" src="http://2.bp.blogspot.com/_q4vdH9mlCeg/SprZtjHvYXI/AAAAAAAAAC4/oeu64R9UZag/s200/kurtosis_curve.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5375848481765155186" /></a><br />The first signal, in blue, took 47 iterations to reach the stopping criteria. The second signal, in green took only about 17 iterations to stop (the fall off in the green curve is just an artifact of the way the data is stored). As you can see, both of the curves start off fairly steep and rapidly level out. Each curve represents the slop of the gradient as it is pursued uphill. <br /><br />You can see some interesting effects by changing the parameters to the function. It is possible, for example, to get the algorithm to oscillate around the peak of kurtosis as each probe overshoots the peak.<br /><br />The reason we have less than perfect demixed signals is because we can never hit the peak kurtosis perfectly. As we get closer to the peak, the magnitude of the gradient gets smaller and smaller, so that the demixing vector moves by smaller and smaller amounts. The smaller we set the "tol" parameter, the closer we can get, at the expense of more iterations.<br /><br />So, in retrospect, this example mix is not so great because the demixed signals appear to be orthogonal. However, they aren't. The resulting demixing vectors are [0.7665,-0.644225], and [0.70813,0.70608]. Their dot-product is 0.087907. So, they are close, but not quite, orthogonal. This is important. One of the benefits of projection pursuit is that it can find signals that are not orthogonal. Other simple analysis techniques like <a href="http://en.wikipedia.org/wiki/Principal_component_analysis">PCA </a> (Principal Component Analysis) rely on the signals being orthogonal to produce meaningful results. <br /><br />Here is the raw signal, before projection onto the ortho-normal basis in the first steps of the algorith:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_q4vdH9mlCeg/SprcIMs7W6I/AAAAAAAAADA/WL-eL420Mco/s1600-h/raw_signals.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 144px;" src="http://4.bp.blogspot.com/_q4vdH9mlCeg/SprcIMs7W6I/AAAAAAAAADA/WL-eL420Mco/s200/raw_signals.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5375851138626837410" /></a><br />As you can see, the original signals are not orthogonal. There is no guarantee that the projection onto the ortho-normal basis will produce orthogonal, or near-orthogonal signals. That is just a characteristic of this particular data. <br /><br />Thanks to Dr. Paul Schimpf for comments and suggestions about this posting.<br /><br />For the next installation, I'll examine how to get started writing this in haskell.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-34913398716777260162009-08-21T10:36:00.000-07:002009-08-21T13:32:37.876-07:00Projection Pursuit in Haskell, pt 1In the Spring Quarter, I took a class called Introduction to Scientific Computing. It was sort of a survey of scientific computing techniques focused on using <a href="http://www.gnu.org/software/octave/">Octave.</a><br /><br />Our final project was to implement a <a href="http://davis.wpi.edu/%7Ematt/courses/nland/node4.html">Projection Pursuit</a> algorithm to unmix two or more mixed sound signals using the same number of mixes as there were signals. The idea is simple: Given, say, two speakers and two microphones, all at different locations, if the two speakers each play different sounds then the two microphones will detect different mixes of those two sounds. Our job was to take these two mixes and "unmix" them. For simplicity's sake, we are ignoring the time differential that would occur between the different mixes.<br /><br />To do this using Projection Pursuit, we project the two mixes onto a random vector in 2 dimensional space. Then we measure the <a href="http://en.wikipedia.org/wiki/Kurtosis">kurtosis</a> of the projected signal. Next, we do a gradient ascent, adjusting our vector to climb uphill in the direction of the greatest kurtosis. As we approach the peak, the change in kurtosis gets smaller and smaller. When we satisfy our stopping criteria (the change in kurtosis falls below some threshold) we consider a signal to be "found". Then we extract the signal that lies on that vector and we have our first unmixed sound. Next we remove that signal from the two mixes and what remains is the other sound. This works because sounds tend to be super-gaussian signals, so the kurtosis will climb fairly quickly as you search.<br /><br />I have to say, it was a really cool project and sort of "magical" when the extracted sounds started playing.<br /><br />My goal is to port this project to Haskell. Projection Pursuit can be implemented, I believe, in purely functional code as fairly straightforward recursion. Now there are certain niceties to doing the original in Octave: native matrix and vector manipulation, simple graphing capabilities (so you can watch it "pursue"), and fairly easy sound playing to listen to the results. I probably won't get to coding up the graphing and sound in Haskell.<br /><br />I completed some portions of the matrix manipulation functions earlier in the summer, but it's not ready to post yet, and I want to write up my progress in this process.<br /><br />Next time, I'll post my Octave code, and provide some graphics of the pursuit. It's pretty cool.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com3tag:blogger.com,1999:blog-3349594275407898736.post-16818267463011384102009-07-02T05:05:00.001-07:002009-07-02T06:56:15.342-07:00How do you TODO?Some time back there was an ask <a href="http://www.reddit.com/r/programming">proggit</a> looking for ideas for handling <a href="http://www.reddit.com/r/programming/comments/8nv63/ask_proggit_how_do_you_todo/">TODO</a>'s. Someone posted a simple <a href="http://www.reddit.com/r/programming/comments/8nv63/ask_proggit_how_do_you_todo/c09vld4">bash script</a> that handled a TODO file in the local directory. Now, I'm always looking for little things to do in Haskell as learning exercises and this one struck me. So, here it is, my TODO program. It actually has a neat bonus feature in that it doesn't display TODO items that are marked with a "DONE". Someday I need to add a date/time stamp, but it's good enough for now.<br /><blockquote><code style="font-size: 80%;">module Main( main ) where<br /><br />import System ( getArgs, system, exitWith )<br />import System.Console.GetOpt<br />import System.Posix.Files<br /><br />main:: IO()<br />main = do<br /> args <- getArgs<br /><br /> case getOpt RequireOrder options args of<br /> ([Edit], _, []) -> spawnEditor <br /> ([Help], _, _) -> putStrLn \$ usageInfo header options ++ description<br /> ([], [], []) -> displayTodo <br /> ([], nonOpts, []) -> addTodo nonOpts<br /> ([], [], msgs) -> error \$ concat msgs ++ usageInfo header options ++ description<br /> _ -> error \$ usageInfo header options ++ description<br /><br /><br />data Flag = Edit | Help<br /><br />options :: [OptDescr Flag]<br />options = [ <br /> Option ['e'] ["edit"] (NoArg Edit) "edit the todo list",<br /> Option ['h'] ["help"] (NoArg Help) "display this help"<br /> ] <br /><br />header :: String<br />header = "Usage: todo [OPTIONS] [todo item]"<br /><br />description :: String<br />description = unlines [ ""<br /> , "The default operation is to just cat the TODO file. Calling todo with"<br /> , "a non-option argument will add that argument to the TODO file."<br /> ]<br /><br />todoFile :: String<br />todoFile = "TODO"<br /><br />-- TODO -- needs to check for existing emacs process first and run emacsclient in that case...<br />spawnEditor :: IO ()<br />spawnEditor = system ("emacs " ++ todoFile) >>= exitWith<br /><br />addTodo :: [String] -> IO ()<br />addTodo nonOpts = do<br /> print "Updating todo list..."<br /> appendFile todoFile \$ (unwords nonOpts) ++ "\n"<br /><br />displayTodo :: IO ()<br />displayTodo = fileExist todoFile >>= <br /> (\a -> if a <br /> then readFile todoFile >>= putStr . removeDones<br /> else putStrLn "nothing to do!") <br /><br />removeDones :: String -> String<br />removeDones = unlines . filter (not . contains "DONE") . lines <br /><br />contains :: String -> String -> Bool<br />contains target source = any (== target) \$ words source<br /><br /></code></blockquote><br /><br />It's not the greatest Haskell code I'm sure, but its the first I've done that wasn't pure functional code, it works, and was fun to sort out.<br /><br />ps. Looks like my attempts at formatting code were less than fully successful. It's all there, just click and drag to select it... sorryAndrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-53866794363949136912009-04-14T14:59:00.000-07:002009-04-14T15:11:16.676-07:00Linear linear everywhere....We had the distinct pleasure of being lectured by Dr. Ron Gentle last week as our regular Calc IV(multi-variable) professor was out of town for two days. Dr. Gentle is known for viewing the entire universe as a linear construct of some sort or another and the subject matter for his lectures, multi-variable chain rule differentiation, was no exception, being distilled down to a simple vector multiplication for any possible type of differentiation out there. I'll probably talk more about that later, but the main point is that Dr. Gentle is right, linear algebra is *everywhere*.<br /><br />A case in point was today's lecture (from the usual guy, Dr. Dale Garraway) on directional derivatives. To make a long story short, we have already worked through partial derivatives where given $f(x,y)=x^2+y^3$, the first partial derivative in the $x$ direction is $f_x(x,y)=2x$ and the first partial in the $y$ direction is $f_y(x,y)=3y^2$.<br /><br />Great, but what if you want to know the derivative in some other direction, like, say, in the direction of the vector $\vec{v}=(a,b)$? The general answer is this: $f_{\vec{v}}(x,y)=f_x(x,y)a + f_y(x,y)b$. The astute reader will notice that this is just a linear combination of the two first derivatives. Could it be that the first derivatives just form a basis for a function space defining all the derivatives of this multi-variable function? It sure looks like it.<br /><br />In fact it looks like essentially a basis conversion from a spatial basis (the vector in $\mathcal{R}^2$ or something like that) to a functional basis giving the derivative. Neat.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-53212407055106311302009-03-29T13:44:00.000-07:002009-03-29T13:56:49.602-07:00Polynomials with Function CompositionThis morning, reading in <a href="http://www.cs.man.ac.uk/~david/categories/">Computational Category Theory</a>, by Rydeheard et al, I came across this little piece of ML (it's pretty early in the book. It takes me about 45 minutes to read a page, sheesh):<br /><br /><code><br /> fun poly_eval(f) = f(f(3)) + f(3) + 3<br /></code><br /><br />And I got to thinking about how this looks like a linear combination of function compositions. I just finished Linear Algebra so everything looks linear. One of the things I've been trying to wrap my head around is how to express function composition in a linear manner, and while this posting won't address that directly, it may help me down that road. <br /><br />The question today is how to express polynomials as composition, as in the code above. <br /><br />Given a standard form for a degree two polynomial: $f(x)=a_1x^2+a_2x+a_3$, let's replace every occurrence of $x$ in the polynomial with a function that multiplies $x$ by its argument. Composing this function with itself would multiply the value of $x$ by something multiplied by the value of $x$.<br /><br />Sort of like this:<br /><br />let $f=\lambda a. ax$ where $a$ is the coefficient of the polynomial term. Here $x$ is a free variable and if we provide a coefficient $c$, the result is $cx$. If we compose these functions we can expand them and see what happens.<br /><blockquote>$\begin{eqnarray} f(f) & = & f (\lambda a. ax)\\& = & (\lambda b. bx)(\lambda a.ax)\\\end{eqnarray}$</blockquote><br />now apply a constant $c$ as our coefficient, and evaluate<br /><blockquote>$\begin{eqnarray} f(f c) & = & (\lambda b. bx)(\lambda a.ax) c\\& = & (\lambda b.bx)(cx)\\& = & (cx)x\\& = & cx^2\end{eqnarray}$</blockquote><br /><br />and there we have our first term in our polynomial (I'm not up on $\lambda$-notation and such stuff, so please, someone correct me if I've made a mistake in the above).<br /><br />We can express this in code (thanks to dolio on #haskell) by adopting the convention that $f$ will accept a function and a value where the value will become our free variable (using partial application) and the function will either be other $f$'s (composition) or $const$ $c$, the coefficient.<br /><code><br /> f::(Num a) => (a -> a) -> a -> a<br /> f g x = g x * x<br /></code><br />and these can be composed as many times as we like to get powers of $x$.<br /><code><br /> *Main> let two_x2 = f(f(const 2))<br /> *Main> :t two_x2<br /> two_x2 :: Integer -> Integer<br /> *Main> two_x2 5<br /> 50<br /></code><br />Unfortunately, this forces us to declare the coefficient in advance and then we're stuck with it. It would be nice to be able to decide the coefficient later and still have $x$ as a free variable.<br /><br />We can do it like this:<br /><code><br /> x1 = \c -> f(const c)<br /> x2 = \c -> f(f(const c))<br /></code><br />Now both $x1$ and $x2$ (for $x$ and $x^2$) can be used to express a polynomial term with an arbitrary coefficient.<br /><code><br /> *Main> :t x2<br /> x2 :: Integer -> Integer -> Integer<br /> *Main> let five_x2 = x2 5<br /> *Main> :t five_x2<br /> five_x2 :: Integer -> Integer<br /> *Main> five_x2 4<br /> 80<br /> *Main> five_x2 2<br /> 20<br /></code><br /><br />Finally, it is simple to build arbitrary polynomials with a free variable<br /><br /><code><br /> poly = \a1 a2 a3 x -> x2 a1 x + x1 a2 x + a3<br /></code><br />where $a1, a2, a3$ are the coefficients. Using partial application we can create a specific polynomial with its coefficients and then apply it to any value for $x$ that we like.<br /><code><br /> *Main> let polyA = poly 1 2 3<br /> *Main> :t polyA<br /> polyA :: Integer -> Integer<br /> *Main> polyA 5<br /> 38<br /></code><br /><br />Here, $polyA(x) = x^2 + 2x + 3$. There we go, arbitrary polynomial expression using function composition. I suppose this is pretty simple stuff, but I find it incredibly fascinating. I'm hoping this will have some application to my thoughts on linear transformations of functions with composition.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0tag:blogger.com,1999:blog-3349594275407898736.post-33484738480296469832009-03-22T06:11:00.000-07:002009-03-29T13:55:17.475-07:00Partial Fraction Decomposition with Linear AlgebraThe first semester of linear algebra is an eye-opening lesson in the applicability of mathematics and in the concepts of abstraction. Moving from linear transformations and operators on simple vectors in $\mathcal{R}^2$ or $\mathcal{R}^3$ to the same in general vector spaces is amazing. Extending these ideas into more abstract realms clearly shows the math in something like compilation of computer programs. What is compilation other than a transformation from one vector space (the source code) to another (the object code)? Wow!<br /><br />Anyway, there were a number of interesting little problems that presented themselves near the end of the semester. One fellow student asked if we could consider partial fraction decomposition as a linear operation. The question was never adequately answered in class (merely due to a misunderstanding, $M^2$ still rocks!), but I think I've worked out one decent version of it.<br /><br />First, to review, partial fraction decomposition is the process of turning a rational fraction into a sum of simpler, partial, rational fractions. That is, moving from <br /><blockquote>$\begin{eqnarray} \frac{4x+6}{x^3+6x^2+11x+6} \end{eqnarray}$</blockquote><br />to<br /><blockquote>$\begin{eqnarray} \frac{1}{x+1}+\frac{2}{x+2}-\frac{3}{x+3} \end{eqnarray}$</blockquote><br /><br />In this example, we are using a relatively straightforward, easily factorable, denominator with a degree greater than that of the numerator. Honestly, I haven't, at this point, worked out the details for some of the other types of partial fraction decomposition.<br /><br />The above decomposition is typically worked out by first factoring the denominator into distinct linear factors, setting up a sum of those factors with variables in the numerators, and multiplying by a common denominator. The result is an equation with the original numerator on the left and polynomial expressions on the right.<br /><br /><blockquote>$\begin{eqnarray} \frac{4x+6}{x^3+6x^2+11x+6} & = & \frac{4x+6}{(x+1)(x+2)(x+3)}\\ & = & \frac{A}{x+1}+\frac{B}{x+2}+\frac{C}{x+3}\\ 4x+6 & = & A(x+2)(x+3)+B(x+1)(x+3)\\ & & +C(x+1)(x+2)\end{eqnarray}$</blockquote><br /><br />At this stage, we expand all the expressions on the right, regroup like terms and extract a set of equations representing the coefficients of like terms as follows<br /><br /><blockquote>$\begin{eqnarray} 4x+6 & = & A(x^2+5x+6)+B(x^2+4x+3)+C(x^2+3x+2)\\ 4x+6 & = & (A+B+C)x^2+(5A+4B+3C)x+(6A+3B+2C)\\\end{eqnarray}$</blockquote><br /><blockquote>$\begin{eqnarray} A+B+C & = & 0\\ 5A+4B+3C & = & 4\\ 6A+3B+2C & = & 6\end{eqnarray}$</blockquote><br /><br />Now we just solve the system of equations using any method we like to find the three values to use as numerators in the decomposition. It is easy to see a linear solution. We have a system of three equations with three unknowns. We could easily solve this using an augmented coefficient matrix and row reduction.<br /><br />But there is a better way. Back up to this step.<br /><br /><blockquote>$\begin{eqnarray} 4x+6=A(x^2+5x+6)+B(x^2+4x+3)+C(x^2+3x+2)\end{eqnarray}$</blockquote><br /><br />If you think about this for a minute, this looks rather like a representation of one expression, the polynomial on the left, in terms of a different set of polynomials on the right. And in fact, it is. Also note that the polynomials on the right are the expansions of each multiplicative combination (less one) of the linear factors of our original denominator.<br /><br />We can look at this as a coordinate change operation. The expression on the right is a coordinate vector of the expression on the left in some basis other than the standard basis for $P$ (polynomials). If you don't see it yet, you will, so follow along.<br /><br />One way to represent polynomials is as a vector whose elements represent the various terms in a standard polynomial. This is a basic linear transformation often used in linear algebra texts. It looks like this.<br /><br /><blockquote>$\begin{eqnarray} & T : P^2\rightarrow\mathcal{R}^3\\ & T(f(x)) = \left[ \begin{array}{c} a_1\\ a_2\\ a_3 \end{array}\right]\end{eqnarray}$</blockquote><br /><br />where<br /><blockquote>$\begin{eqnarray} f(x) = a_1 + a_2x + a_3x^2\end{eqnarray}$</blockquote><br /><br />Using this common transformation, we can rewrite each polynomial in our equation above as a vector in $\mathcal{R}^3$.<br /><br /><blockquote>$\begin{eqnarray} 4x+6 & = & \left[ \begin{array}{c} 6\\4\\0 \end{array} \right] \\x^2+5x+6 & = & \left[ \begin{array}{c} 6\\5\\1 \end{array} \right] \\x^2+4x+3 & = & \left[ \begin{array}{c} 3\\4\\1 \end{array} \right] \\x^2+3x+2 & = & \left[ \begin{array}{c} 2\\3\\1 \end{array} \right]\end{eqnarray}$</blockquote><br /><br />And now it is quite clear that this is a basis change, expressing a vector in terms of a different basis.<br /><br /><blockquote>$\begin{eqnarray} \left[ \begin{array}{c} 6\\4\\0 \end{array} \right] = A\left[ \begin{array}{c} 6\\5\\1 \end{array} \right] + B\left[ \begin{array}{c} 3\\4\\1 \end{array} \right] + C\left[ \begin{array}{c} 2\\3\\1 \end{array} \right]\end{eqnarray}$</blockquote><br /><br />We can develop a coordinate change matrix $[T]_{\mathcal{B}}$ as the inverse of the concatenation of the vectors on the righthand side. In coordinate changes, we use the equation $[T]_{\mathcal{B}}\vec{v_{\mathcal{B}}}=\vec{v}$. With this we can easily solve this partial fraction decomposition thus<br /><br /><blockquote>$\begin{eqnarray}& [T]_\mathcal{B} = \left[ \begin{array}{c c c} 6 & 3 & 2\\ 5 & 4 & 3\\ 1 & 1 & 1 \end{array} \right]^{-1} = \left[ \begin{array}{c c c} \frac{1}{2} & -\frac{1}{2} & \frac{1}{2}\\ -1 & 2 & -4\\ \frac{1}{2} & -\frac{3}{2} & \frac{9}{2} \end{array} \right] \\& \vec{v_{\mathcal{B}}} = \left[ \begin{array}{c} 6\\4\\0 \end{array} \right] \\& [T]_\mathcal{B}\vec{v_{\mathcal{B}}} = \left[ \begin{array}{c c c} \frac{1}{2} & -\frac{1}{2} & \frac{1}{2}\\ -1 & 2 & -4\\ \frac{1}{2} & -\frac{3}{2} & \frac{9}{2} \end{array} \right] \left[ \begin{array}{c} 6\\4\\0 \end{array} \right] = \left[ \begin{array}{c} 1\\2\\-3 \end{array} \right] = \left[ \begin{array}{c} A\\B\\C \end{array} \right]\end{eqnarray}$</blockquote><br /><br />and use the $A$, $B$, $C$ result to complete our decomposition as<br />before<br /><br /><blockquote>$\begin{eqnarray} \frac{4x+6}{x^3+6x^2+11x+6} & = & \frac{1}{x+1}+\frac{2}{x+2}+\frac{-3}{x+3}\\\end{eqnarray}$</blockquote><br /><br />Well, this is certainly a lot of work for a single application. But, using $[T]_\mathcal{B}$, we can perform any partial fraction decomposition for a rational fraction with this denominator by simple matrix multiplication. In other words, we can repeat this operation, using a different numerator, easily and quickly by plugging in the vector representation of the new numerator above. This should work for any numerator with a degree equal or less than that of the denominator.<br /><br />Likewise, being an invertible operation, we can add any decomposed fractions with these factors as denominators without the tedious polynomial expansion commonly used. We simply multiply $[T]_{\mathcal{B}}^{-1}$ by the vector representation of $A$, $B$, $C$ and it will spit out the vector form of the numerator. Cool!<br /><br />This technique really only works, at this point, for rational fractions with easily factored denominators. It may be extendable for use in other cases, but I haven't done the work yet to investigate how easy that might be.Andrew Sackville-Westhttps://plus.google.com/103735280604685354305noreply@blogger.com0