Initial add of the generic optimizer code

Before digging into this code, look at the Rules implemented at the bottom of DagOptimizer.

There are several TODOS here:

- [x] After I split the code into separate files, I started hitting a scala 2.9 compiler bug, that I don't hit in 2.10. I'll try to work around, or possibly hope that Twitter finally gets on 2.9 before we need this.

- [x] Tests tests tests. I played around at the repl, but clearly we need super hardcore tests for any optimization framework.

- [ ] Actually call this code from an existing platform.
Ok, yeah, that's exactly what I meant. On more reflection, keeping it ```Set[Id[_]]``` makes sense in the spirit of using typed-ness where possible (ie not accidentally putting the wrong type in).

I guess my point was mainly this: yes, it is a ```Set[Int]```, so that could be used... but more generally, since ```Id[T]``` is a phantom type, once you enter wildcard land, it'll never be useful again. So I'm not sure what it even represents anymore, as we have two ideas here: one is the Id, and one is the phantom type the Id carries with it in some cases. This is the source of confusion. We may pull an Id out of the set, but once we've become Id[_], what does that type even mean? It seems we're conflating those two uses.

But I am not sure. Would love your thoughts.