Sunday, November 29, 2009

More LaTeX On The Web












Sometimes I find myself in need of a GIF image of an equation or two. I want to be able to generate them quickly and easily, but I find that my MikTeX setup on Windows isn't helping.

Fortunately, Google found a utility that converts LaTeX to an image at EquationSheet.com. All I have to do is type in a snippet of LaTeX, hit the "convert" button, and I can see the equation rendered as an image. Even better, I can copy the URL and paste it into another HTML page as an image tag. Just what the doctor ordered!



Saturday, November 21, 2009

Coders At Work










I finished reading Peter Seibel's Coders At Work: Reflections on the Craft of Programming yesterday. I thought it was terrific and would recommend it highly to anyone who writes code for a living. It's an impressive follow-up to his Practical Common Lisp.

Peter drew his inspiration from the Paris Review Writers At Work. Great creativity is required to recognize an idea that's good in one context and reuse it in another.

The roster of interviewees is impressive, especially after having read the book. I only knew a minority when I opened the book. Only Knuth and Ken Thompson were long-familiar names. I knew of JWZ by hearsay. I have a copy of Peter Norvig's "AI: A Modern Approach", it's been over my head forever.

Donald Knuth is the biggest name; Peter holds him back for the last chapter. He seemed to me to be from another planet. I've written about my love of LaTeX; this is the man who spent ten years of his life coming up with TeX. I especially liked this bit on page 598:


With TeX I was interacting with hundreds of years of human history and I didn't want to throw out all of the things that book designers have learned over the centuries and start anew and say, "Well, forget that guys; you now, we're going to be logical now."


The more I learn about Peter Norvig, the more impressed I am. The people who are exposed to his genius at Google are fortunate indeed.

Guy Steele didn't disappoint. He's brilliant, but he can't help working the fact that he went to MIT into the very first answer he gives. My informal survey tells me that this is true of each and every MIT graduate I've ever known personally - except for one. (My friend is one of the most brilliant, most accomplished people I know, but I didn't hear that his Ph.D. came from MIT until after I'd known him for a long time, until I heard it from a mutual friend.) Thank you for another data point, Guy.

Some of these folks are younger than I am, but most are my contemporaries. All are far more accomplished as programmers and computer scientists than I am. They were doing their best work in this field when I was a mechanical engineer. I'm doing my best to try and catch up, but I still have a very long way to go. I envy them their accomplishments.

It seems to me that Peter Seibel struck a very nice balance between scripting his questions and letting the conversation lead him. There was a thread of common questions that ran through all the interviews (e.g., "How do you debug?", "Do you read code?", "Do you consider yourself a scientist, engineer, craftsman, or artist?", "How much math is needed to be a good programmer?"), but each interviewee contributed special insights that would have been hard to anticipate.

The book brought home two things to me: how much computing has changed since these people were in their heydays and how much wonderful stuff is being lost to time. I haven't read "The Art of Computer Programming". I feel like I should, but I'm not sure that it'll provide a payoff for all that effort in the corporate enterprise computing world in which I earn my living today. Those with the talent and good fortune to be working for Google and firms that value deep knowledge are a minority.

Every one of the individuals interviewed by Peter Seibel is a giant in the field. Is that so because they did their best work early in the history of computer science? If 2% of people are wired to be programmers, and there are 6.67 billion people on earth, that means there are about 133,400,000 potential writers of C#, Java, Cobol, Lisp, or what have you. Will we find giants to compare to the early ones?

I've read that Shakespeare and Babe Ruth stood out in their fields because there were comparatively fewer contemporaries who were their equals. Now that we have everyone blogging on the Internet and full-time professional athletes it's harder to stand out.

Programming is often compared to building buildings or manufacturing widgets or god knows what else. Like these other productive activities, it's often outsourced by American firms to be done by individuals in parts of the world that will do it for far less than their domestic counterparts. Will the next generation of great achievers come from their ranks? Will Peter Seibel have to travel further afield to hear about their exploits?

I enjoyed the book very much and recommend it highly.


Wednesday, November 11, 2009

Raking Leaves










The weather on the East Coast was unseasonably beautiful this weekend. It was sunny and warm both on Saturday and Sunday. It afforded me an opportunity to get the leaves off my yard and into a pile in the woods. My lot is 1.1 acres, with woods separating my house from the one behind me. There's a mountain of leaves taller than me in those woods tonight. It grew one tarp load at a time over the course of two days.

I always think of my father when I rake leaves. Some kids went to ball games with their dad; I raked leaves with mine.

He was an Irish immigrant who came to this country with the equivalent of a high school education. He got a job working for the water company in town. He was a member of the crew that worked to maintain the system of pipes and valves buried under the roads. They led from the treatment plants situated next to the reservoirs to the metered 1" diameter copper pipes that were the "last mile" into each and every house in town. He knew every pipe, both size and material, every valve in the system, because he had either put them in place or repaired them at one time or another. He had an unmatched encyclopedic knowledge of roads in town. He could associate each one with one job or another: "We had an 8 inch main break on Sinoway Road last night."

It was a good union job, but with six kids at home he didn't mind hustling for a few extra bucks. So on Saturdays he would go out and do yard work for people. He had regular customers that would have him cut the grass in the summer and rake the leaves in the fall. It meant getting up early on Saturday mornings and spending the day going from house to house. The last stop was always my grandmother's.

I was his eldest son. By my best recollection I was nine or ten years old the first time I went with him on a Saturday morning. I was less than useless. I didn't have the strength or stamina to help much in the beginning, but young legs can serve a purpose when you don't want to walk back to get a tool. He was easing me into the idea of helping.

As I became capable of contributing more, I remember going more frequently. I can't recall anymore how regular I was about the task. I'm sure that my faithfulness fell short. But I do remember going on more than a haphazard basis. I knew the names of all the customers, and they knew me. I can still point out the houses that haven't fallen victim to time and been knocked down to make way for McMansions.

These were quiet trips. We'd both get up early on Saturday mornings, load the appropriate tools into the car, and go on our appointed rounds. We didn't get coffee or chat a lot. He would thank me for helping, but whatever checks exchanged hands went into his pocket. I never questioned the arrangement. It was understood that it was my duty to help.

My father was very methodical and meticulous about raking leaves. He always had a large tarp that we'd spread out on a part of the lawn that was covered with leaves. "Don't rake onto a piece that you've already cleaned," he'd tell me. He would start in one corner and work in one direction, sweeping the area until there wasn't a leaf to be seen. He bought a gas-powered blower, the first one that I'd ever seen, that would speed the work and spare our hands the raking until we had a pile worthy of pushing into the tarp to be carried away.

After I went to college I didn't join him on Saturdays anymore. It's been too long - I can't pinpoint when he gave it up. Perhaps it was after my grandmother passed away. I never asked if the task fell to either of my younger brothers when I dropped the torch. I don't remember any of them joining us on Perryridge Road.

As I look back on it now, I like to think that I was chosen to go because I had the temperament for it. Maybe he liked doing it with me as much as I was proud to be chosen by him. It was something that I did with my father that no one else did.

Some kids went to ball games with their dad; I raked leaves with mine.

I still carry that experience with me to this day. I rake leaves the way he taught me. He would have been happy with my handiwork this weekend. At the end of a day of work - the sky red from the setting sun; the chilled air reminding me that it's the waning of another year; the dead silence at the end of a late autumn day - I think of my father.


Monday, November 9, 2009

When Everything Changed










I've finished reading Gail Collins' "When Everything Changed: The Amazing Journey of American Women From 1960 To The Present."

Amazing, indeed.

I've lived through the period described by the book, although I was awfully young for the earliest years. I remembered as I read, but having the changes spelled out so clearly was astonishing. Seeing how much has changed in such a short period of time, I had a feeling of disbelief as I read: "Did we really live like that? Is that what people thought back then?"

I can't fully identify because of my gender, but I can appreciate the difference as the father of two daughters. My sisters had to fight the good fight to go to college; my daughters grew up with the expectation that they'd go. Such a difference in the span of one or two generations.

Gail's writing style mirrors her columns on the editorial pages of the New York Times: part historian, part educator, part wry observer, all glued together by a dry wit. I happen to love it. I laughed out loud in places.

Of course I'll have my daughters read the book. It'll be a good lesson for them to see how their choices have expanded. I recommend it highly.


Sunday, November 8, 2009

jsMath: Typesetting Math In A Browser










I just became aware of jsMath, a JavaScript library from the Math Union for typesetting mathematics in a browser.

The content from the web site says it far better than I will, but it looks like jsMath was inspired by the slow adoption of MathML support in browsers running under Windows, Mac, and *nix machines.

The examples that the web site offers look beautiful. It's based on TeX, so it's no surprise that the results look so good. I didn't get a chance to dive into it this weekend. Unseasonably nice weather on the East Coast made it possible for me to clean up all the leaves that were covering my yard, so time to program was hard to come by. But I'll be looking into this gem soon. It's a nice complement to my recent rediscovery of LaTeX.

It amazes me to see how smart people can come up with things like this. It's also another example of the increasing reach of JavaScript. Brendan Eich's language is becoming more important every day.


Thursday, October 29, 2009

A New Old Idea









This blog entry is different from all the others I've posted to date. Whenever I've uploaded a photo, I've gotten it by searching Flickr.com Creative Commons for something that fit the theme of the post.

I took the picture that accompanies today's entry. I wanted to try something new.

Writer's block is a problem for me. I've had trouble for a while with finding my voice here. I love to write, but I've had a hard time making up my mind what I should focus on. A purely technical blog, like Jeff Atwood's Coding Horror, would be worthwhile, but I have a hard time filtering out more personal and non-technical thoughts. I feel a little exposed putting too much personal information out on the Internet. The frequency of posts shows my problem: when I have long gaps, I'm having trouble coming up with a topic.

The funny thing is that inspiration is all around us. I see all kinds of small details that are interesting to me. But they're often forgotten in the bustle of getting through busy weeks.

I used to keep an electronic journal. I have entries dating back to 1994 that comprise a special personal history. Sadly, it's fallen into decay. I don't have the same inspiration for it.

At one time I thought that learning to draw from Betty Edward's wonderful "Drawing On The Right Side Of The Brain" would be my inspiration. I did the exercises faithfully. I would draw random things while sitting in meetings, just to hone my skills, my eye, and the shift to right-brain mode. I loved it - until I hit the chapter on portrait drawing. My left brain was too critical. I couldn't find a way to quiet it. I would still love to find a way over the barrier, but to date I've been unsuccessful.

I have learned how to adopt ideas from people who are smarter than me. I have no problem emulating and following when I see someone doing something that I admire.

I went to Boston this past weekend to see the just-completed renovation job on my beloved second sister's house (it's spectacular). My beloved oldest sister was taking photos using a Fuji digital camera that had a big view finder, took great photos, and fit into a shirt pocket. I've never been a photographer. I've tried to concentrate on experiencing the moment rather than preserving it. But watching her snap away unobtrusively made me think "I could do that, too."

So I went out the other night and picked up a Fuji Finepix J38 - same model as hers; same color, black. Did I say "no problem emulating"? That meant "slavishly copying." I grabbed a case sturdy enough to protect the view finder and still slide into a pocket without looking too bulky. ("Is that a Fuju Finepix J38 in your pocket or are you just glad to see me?")

My idea is that I'll try to have the camera on hand as much as possible. If I see something interesting, I'll snap it, upload it later, and perhaps write about it here. I'm not going to worry so much about what comes out; I'm going to just keep practicing and writing.

I failed at drawing; now this jewel of technology will be my cache for ideas. It's got to piss off every truly skilled photographer who has spent a lifetime mastering film, technology, light, developing techniques, and the all-important artist's eye. Digital cameras have become so cheap and so good that any fool can trick themselves into thinking that they're Ansel Adams.

I tried it this morning when I went to work. The light and the view when I came out of the pool before work was enticing, so I unselfconsciously took out my camera, stood on the sidewalk, and snapped away. I took a few on the way out as well. I liked this picture the best of all.

I'm going to emulate my beloved, beautiful, brilliant eldest daughter, too. She's been writing a blog on street art for almost a year. The amazing thing about it, besides the content, is that she posts an entry every single weekday, without fail.

How does she do it? By treating it like a job. She lines up her sources, writes the pieces, and queues them up for daily release. Her dedication, discipline, and work ethic are as impressive as the material she elicits from all over the world.

I'd like to try that, too. I need to be more focused on what I'm pumping out there. I shouldn't have only one or two posts per month. I can do better.

What does all this mean? Probably nothing. I'm just another guy on the Internet, taking pictures and blabbing about himself, putting it out because Blogger makes it easy, thinking that it's terribly interesting and world-changing. How self-indulgent and boring! Right?

I'll concede that point.

I like the mental stimulation of trying to do something that I've never done. I want to keep thinking and challenging myself. I prefer this to coming home and settling in front of a television every night. I don't bloody well care if anybody notices. I'm doing this solely for myself, for its own sake.

Saturday, October 24, 2009

Binary Tree Iterators










In my last post, I presented code (and unit tests) for a binary tree implementation in Java. I alluded to the fact that there was a depth-first iterator in one of the test classes. This time I'll discuss iterators and present more practice code.

Iterator is one of the behavioral patterns described by the Gang of Four in their classic "Design Patterns". It provides the means for walking through a data structure without having to expose the details of how it's done.

Timothy Budd provides an excellent explanation of binary trees and iterators in chapter 10 of his "Classic Data Structures In C++".

Binary trees are interesting data structures. If the n nodes in a binary tree are independent, then there are n! = n*(n-1)*...*2*1 different orderings by which one could visit every node.

But the fact that the tree is arranged so that each parent has, at most, a left and right child limits the number of choices for walking the tree to six:

  1. Process value, then left child, then right child
  2. Process left child, then value, then right child
  3. Process left child, then right child, then value
  4. Process value, then right child, then left child
  5. Process right child, then value, then left child
  6. Process right child, then left child, then value


Subtrees are usually traversed from left to right, so the first three possibilities are the most common. Each is given a name that may be more familiar and memorable. The first is called preorder or depth-first traversal; the second in-order or symmetric traversal; and the third post-order traversal. There is also level order or breadth-first traversal, where all the nodes at one level are visited before proceeding to the next.

Java has an Iterator interface in its java.util package that defines the methods that all classes that implement it must provide. The next() returns a generic value. For my binary tree iterator I knew there'd be times when I wanted to get the next Node instead of the value, so I extended the Iterator interface and added a next method that returned a Node<T>:

package tree;

import java.util.Iterator;

public interface BinaryTreeIterator<T extends Comparable<T>> extends Iterator<T>
{
Node<T> nextNode();
}


Then I created an abstract class that provided default behavior for all methods except the ones that provided the next Node value and whether or not the walk through the tree was complete:

package tree;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Iterator;

public abstract class AbstractBinaryTreeIterator<T extends Comparable<T>> implements BinaryTreeIterator<T>
{
public static final Log LOGGER = LogFactory.getLog(AbstractBinaryTreeIterator.class);

public void remove()
{
throw new UnsupportedOperationException("cannot remove from a binary tree");
}

public T next()
{
Node<T> nextNode = nextNode();

return nextNode.getValue();
}
}


The post-order traversal examines the left child first, then the right child, then the value in a recursive manner. It uses a last in, first out (LIFO) stack to hold the nodes in the opposite order they are to be visited. The iteration starts by pushing the root node onto the stack and recursing down the tree:

package tree;

import java.util.NoSuchElementException;
import java.util.Stack;

public class PostOrderIterator<T extends Comparable<T>> extends AbstractBinaryTreeIterator<T>
{
protected Stack<Node<T>> stack = new Stack<Node<T>>();

public PostOrderIterator(BinaryTree<T> tree)
{
init(tree.getRoot());
}

public void init(Node<T> root)
{
if (root != null)
{
stack.clear();
stackChildren(root);
}
}

private void stackChildren(Node<T> node)
{
stack.push(node);
Node<T> next = node.getRight();
if (next != null)
{
stackChildren(next);
}
next = node.getLeft();
if (next != null)
{
stackChildren(next);
}
}

public Node<T> nextNode()
{
if (!hasNext())
{
throw new NoSuchElementException();
}

Node<T> x = null;

if (!stack.empty())
{
if (LOGGER.isDebugEnabled())
{
LOGGER.debug(stack);
}

x = stack.pop();
}

return x;
}

public boolean hasNext()
{
return !stack.isEmpty();
}
}


Of course there are unit tests:

package tree;

import org.springframework.test.context.ContextConfiguration;
import static org.testng.Assert.assertFalse;
import static org.testng.AssertJUnit.assertEquals;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

@Test
@ContextConfiguration(locations = "classpath:app-context.xml, classpath:app-context-test.xml")
public class BinaryTreeIteratorTest
{
public void testHasNextEmptyTree()
{
BinaryTree<String> empty = new BinaryTree<String>();
AbstractBinaryTreeIterator<String> iterator = new DepthFirstIterator<String>(empty);

assertFalse(iterator.hasNext());
}

@Test(expectedExceptions = UnsupportedOperationException.class)
public void testRemove()
{
BinaryTree<String> empty = new BinaryTree<String>();
AbstractBinaryTreeIterator<String> iterator = new DepthFirstIterator<String>(empty);
iterator.remove();
}

public void testNextDepthFirst()
{
Integer[] data = {5, 3, 9, 1, 4, 6,};
BinaryTree<Integer> tree = new BinaryTree<Integer>();
tree.insert(data);

String expected = "5,3,1,4,9,6,";
AbstractBinaryTreeIterator<Integer> iterator = new DepthFirstIterator<Integer>(tree);
String actual = createCommaSeparatedString(iterator);

assertEquals(actual.toString(), expected);
}

public void testNextPostOrder()
{
Integer[] data = {5, 3, 9, 1, 4, 6,};
BinaryTree<Integer> tree = new BinaryTree<Integer>();
tree.insert(data);

String expected = "1,4,3,6,9,5,";
AbstractBinaryTreeIterator<Integer> iterator = new PostOrderIterator<Integer>(tree);
String actual = createCommaSeparatedString(iterator);

assertEquals(actual.toString(), expected);
}

private static String createCommaSeparatedString(Iterator iterator)
{
StringBuffer actual = new StringBuffer(1024);
while (iterator.hasNext())
{
actual.append(iterator.next()).append(',');
}

return actual.toString();
}

@DataProvider(name = "emptyTreeIterators")
public Object[][] createEmptyTreeIterators()
{
BinaryTree<String> tree = new BinaryTree<String>();

return new Object[][]{
{new BreadthFirstIterator<String>(tree)},
{new DepthFirstIterator<String>(tree)},
{new InOrderIterator<String>(tree)},
{new PostOrderIterator<String>(tree)},
};
}


@Test(expectedExceptions = NoSuchElementException.class, dataProvider = "emptyTreeIterators")
public void testNextEmptyTree(AbstractBinaryTreeIterator<String> iterator)
{
iterator.next();
}

public void testNext()
{
String[] data = {"F", "B", "A", "D", "C", "E", "G", "I", "H",};
BinaryTree<String> tree = new BinaryTree<String>();
tree.insert(data);

Map<String, String> expected = new HashMap<String, String>();
expected.put("depth-first", "F,B,A,D,C,E,G,I,H,");
expected.put("in-order", "A,B,C,D,E,F,G,H,I,");
expected.put("post-order", "A,C,E,D,B,H,I,G,F,");
expected.put("breadth-first", "F,B,G,A,D,I,C,E,H,");

String name = "depth-first";
AbstractBinaryTreeIterator<String> iterator = new DepthFirstIterator<String>(tree);
AbstractBinaryTreeIterator.LOGGER.debug(name);
assertEquals(name, expected.get(name), createCommaSeparatedString(iterator));

name = "in-order";
iterator = new InOrderIterator<String>(tree);
AbstractBinaryTreeIterator.LOGGER.debug(name);
assertEquals(name, expected.get(name), createCommaSeparatedString(iterator));

name = "post-order";
iterator = new PostOrderIterator<String>(tree);
AbstractBinaryTreeIterator.LOGGER.debug(name);
assertEquals(name, expected.get(name), createCommaSeparatedString(iterator));

name = "breadth-first";
iterator = new BreadthFirstIterator<String>(tree);
AbstractBinaryTreeIterator.LOGGER.debug(name);
assertEquals(name, expected.get(name), createCommaSeparatedString(iterator));
}
}


Tests are great, but being a visual person I like to be able to see a picture. There's a terrific package called graphviz from AT&T that lets you generate graph plots in an elegant way. I wrote a quick program to walk the binary tree { F,B,A,D,C,E,G,I,H } using an iterator and spit out the dot representation, like so:

digraph simple_hierarchy {
F->B [label="L"]
F->G [label="R"]
B->A [label="L"]
B->D [label="R"]
D->C [label="L"]
D->E [label="R"]
G->I [label="R"]
I->H [label="L"]
}


I can use this as the input to dot.exe to render the tree as .png or .svg file:



I'll post the other iterators next time.

All this work just to answer a single interview question! This tells me that doing it justice would be hard in such a short period of time. I would flunk such an interview.

Thanks to my friend Steve Roach, who was the first person to bring graphviz (and so many other things) to my attention. He's one of the most talented developers I've had the pleasure of working with, but it's his teaching ability that's his greatest strength. He's one of those people who makes everyone around him better. Such intellectual generosity is rare indeed.