diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) Sebastiaan Visser 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,6 @@
+#! /usr/bin/env runhaskell
+
+>import Distribution.Simple
+
+>main = defaultMain
+
diff --git a/data-reify-cse.cabal b/data-reify-cse.cabal
new file mode 100644
--- /dev/null
+++ b/data-reify-cse.cabal
@@ -0,0 +1,18 @@
+Name:             data-reify-cse
+Version:          0.0.1
+Description:      Common Sub-Expression Elimination for graphs generated by Data.Reify.
+Synopsis:         Common Sub-Expression Elimination for graphs generated by Data.Reify.
+Category:         Data, Language
+License:          BSD3
+License-file:     LICENSE
+Author:           Sebastiaan Visser
+Maintainer:       sfvisser@cs.uu.nl
+Cabal-Version:    >= 1.6
+Build-Type:       Simple
+Build-Depends:    base ==3.*, containers ==0.2.*, data-reify ==0.4.*
+
+GHC-Options:      -Wall
+Extensions:       CPP
+HS-Source-Dirs:   src
+Exposed-modules:  Data.Reify.Graph.CSE
+
diff --git a/src/Data/Reify/Graph/CSE.hs b/src/Data/Reify/Graph/CSE.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Reify/Graph/CSE.hs
@@ -0,0 +1,99 @@
+-- |
+-- Module: Data.Reify.Graph.CSE
+-- Copyright: (c) 2009 Sebastiaan Visser
+-- License: BSD3
+--
+-- Maintainer: Sebastiaan Visser <sfvisser@cs.uu.nl>
+-- Stability: unstable
+-- Portability: ghc
+--
+-- This module implements common sub-expression elimination for graphs
+-- generated by the Data.Reify package. The algorithm performs a simple
+-- fixed point iteration and is not optimized for speed.
+--
+-- As an illustration, take this simple datatype representing an embedded
+-- language containing primitives and function application.  The datatype
+-- abstracts away from the recursive points which is common when using the
+-- 'Data.Reify' package.  A fixed point combinator can be used to tie the knot.
+--
+-- >data Val f = App f f | Prim String
+-- >  deriving (Eq, Ord, Show)
+-- >
+-- >newtype Fix f = In { out :: f (Fix f) }
+--
+-- No we can add some useful instances and make the fixed point combinator an
+-- instance of the 'Data.Reify' 'MuRef' class.
+--
+-- >instance Functor Val      ...
+-- >instance Foldable Val     ...
+-- >instance Traversable Val  ...
+-- >
+-- >instance Traversable a => MuRef (Fix a) where
+-- >  type DeRef (Fix a) = a
+-- >  mapDeRef f = traverse f . out
+--
+-- When we now take the following example term in our embedded language we can
+-- see that the `cse` function can eliminate common terms without changing the
+-- semantics. Evidently, we assume our language is referential transparent language.
+--
+-- >myTerm :: Fix Val
+-- >myTerm = In $ (Prim "2" `add` Prim "5") `mul` (Prim "2" `add` Prim "5")
+-- >  where add a b = Prim "+" `app` a `app` b
+-- >        mul a b = Prim "*" `app` a `app` b
+-- >        app a b = App (In a) (In b)
+--
+-- The term @fmap cse $ reifyGraph myTerm@ yields an optimized graph compared
+-- to the normal result of `reifyGraph`.
+--
+-- >with CSE:       without CSE:
+-- >
+-- >(1,App 2 9)     (1,App 2 9)
+-- >(2,App 3 9)     (9,App 10 13)
+-- >(10,App 6 7)    (13,Prim "5")
+-- >(9,App 10 8)    (10,App 11 12)
+-- >(3,Prim "*")    (12,Prim "2")
+-- >(6,Prim "+")    (11,Prim "+")
+-- >(7,Prim "2")    (2,App 3 4)
+-- >(8,Prim "5")    (4,App 5 8)
+-- >                (8,Prim "5")
+-- >                (5,App 6 7)
+-- >                (7,Prim "2")
+-- >                (6,Prim "+")
+-- >                (3,Prim "*")
+
+{-# LANGUAGE TypeFamilies #-}
+module Data.Reify.Graph.CSE (cse) where
+
+import Data.Map (Map, toList, fromListWith, filter, update, mapKeysWith)
+import Data.Reify
+import Prelude hiding (filter)
+import qualified Data.Map as Map
+
+{- | Perform CSE on the input graph. -} 
+
+cse :: (Ord (f Unique), Functor f) => Graph f -> Graph f
+cse (Graph xs root) =
+  let swapped = map (\(a, b) -> (head b, a)) . toList . eliminate $ xs
+  in Graph swapped root
+
+groupById :: Ord k => [(a, k)] -> Map k [a]
+groupById = fromListWith (++) . map (\(a, b) -> (b, [a]))
+
+fixpoint :: Eq a => (a -> a) -> a -> a
+fixpoint f a = let b = f a in if b == a then a else fixpoint f b
+
+eliminate :: (Eq a, Functor f, Ord (f a)) => [(a, f a)] -> Map (f a) [a]
+eliminate = fixpoint eliminate1 . groupById
+
+eliminate1 :: (Eq a, Functor f, Ord (f a)) => Map (f a) [a] -> Map (f a) [a]
+eliminate1 g =
+  case toList $ filter ((>1) . length) g of
+    (term, ids):_ -> update (elimKey ids) term . mapKeysWith (++) (elimVal ids) $ g
+    _ -> g
+
+elimVal :: (Eq a, Functor f) => [a] -> f a -> f a
+elimVal i = fmap (\a -> if a `elem` i then head i else a)
+
+elimKey :: [a] -> b -> Maybe [a]
+elimKey = const . Just . take 1
+
