testBipartiteAdjacencyMapAlgorithm :: IO ()
testBipartiteAdjacencyMapAlgorithm = do
    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.detectParts ============"
    test "detectParts empty                                       == Right empty" $
          detectParts (AM.empty :: AI)                            == Right empty
    test "detectParts (vertex 1)                                  == Right (leftVertex 1)" $
          detectParts (AM.vertex 1 :: AI)                         == Right (leftVertex 1)
    test "detectParts (edge 1 1)                                  == Left [1]" $
          detectParts (AM.edge 1 1 :: AI)                         == Left [1]
    test "detectParts (edge 1 2)                                  == Right (edge 1 2)" $
          detectParts (AM.edge 1 2 :: AI)                         == Right (edge 1 2)
    test "detectParts (edge 0 (-1))                               == Right (edge (-1) 0)" $
          detectParts (AM.edge 0 (-1) :: AI)                      == Right (edge (-1) 0)
    test "detectParts (1 * (2 + 3))                               == Right (edges [(1, 2), (1, 3)])" $
          detectParts (1 * (2 + 3) :: AI)                         == Right (edges [(1, 2), (1, 3)])
    test "detectParts ((1 + 3) * (2 + 4) + 6 * 5)                 == Right (swap (1 + 3) * (2 + 4) + swap 5 * 6" $
          detectParts ((1 + 3) * (2 + 4) + 6 * 5 :: AI)           == Right (swap (1 + 3) * (2 * 4) + swap 5 * 6)
    test "detectParts ((1 + 2) * (3 + 4) * (5 + 6))               == Left [1, 3, 2, 4, 5]" $
          detectParts ((1 + 2) * (3 + 4) * (5 + 6) :: AI)         == Left [1, 3, 2, 4, 5]
    test "detectParts ((1 + 2) * (3 + 4) + (3 + 4) * 5)           == Right (swap (1 + 2) * (3 + 4) + swap 5 * (3 + 4))" $
          detectParts ((1 + 2) * (3 + 4) + (3 + 4) * 5 :: AI)     == Right (swap (1 + 2) * (3 + 4) + swap 5 * (3 + 4))
    test "detectParts (1 * 2 * 3)                                 == Left [2, 3, 1]" $
          detectParts (1 * 2 * 3 :: AI)                           == Left [1, 2, 3]
    test "detectParts ((1 * 3 * 4) + 2 * (1 + 2))                 == Left [2]" $
          detectParts ((1 * 3 * 4) + 2 * (1 + 2) :: AI)           == Left [2]
    test "detectParts (clique [1..10])                            == Left [1, 2, 3]" $
          detectParts (AM.clique [1..10] :: AI)                   == Left [1, 2, 3]
    test "detectParts (circuit [1..11])                           == Left [1..11]" $
          detectParts (AM.circuit [1..11] :: AI)                  == Left [1..11]
    test "detectParts (circuit [1..10])                           == Right (circuit [(2 * x - 1, 2 * x) | x <- [1..5]])" $
          detectParts (AM.circuit [1..10] :: AI)                  == Right (circuit [(2 * x - 1, 2 * x) | x <- [1..5]])
    test "detectParts (biclique [] xs)                            == Right (vertices xs [])" $ \(xs :: [Int]) ->
          detectParts (AM.biclique [] xs :: AI)                   == Right (vertices xs [])
    test "detectParts (biclique (map Left (x:xs)) (map Right ys)) == Right (biclique (map Left (x:xs)) (map Right ys))" $ \(x :: Int) (xs :: [Int]) (ys :: [Int]) ->
          detectParts (AM.biclique (map Left (x:xs)) (map Right ys)) == Right (biclique (map Left (x:xs)) (map Right ys))
    test "isRight (detectParts (star x ys))                       == not (elem x ys)" $ \(x :: Int) (ys :: [Int]) ->
          isRight (detectParts (AM.star x ys))                    == (not $ elem x ys)
    test "isRight (detectParts (fromBipartite (toBipartite x)))   == True" $ \(x :: AII) ->
          isRight (detectParts (fromBipartite (toBipartite x)))   == True

    -- TODO: Clean up these tests
    putStrLn ""
    test "((all ((flip Set.member) $ edgeSet $ symmetricClosure x) . edgeSet) <$> detectParts x) /= Right False" $ \(x :: AI) ->
          ((all ((flip Set.member) $ AM.edgeSet $ AM.symmetricClosure x) . edgeSet) <$> detectParts x) /= Right False
    test "(Set.map $ fromEither) <$> (vertexSet <$> (detectParts (fromBipartite (toBipartite x)))) == Right (vertexSet x)" $ \(x :: AII) ->
         ((Set.map $ fromEither) <$> (vertexSet <$> (detectParts (fromBipartite (toBipartite x))))) == Right (AM.vertexSet x)
    test "fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (vertexSet x) . Set.fromList) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (AM.vertexSet x) . Set.fromList) (const True) (detectParts x))
    test "fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (edgeSet (symmetricClosure x)) . AM.edgeSet . circuit) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (AM.edgeSet (AM.symmetricClosure x)) . AM.edgeSet . AM.circuit) (const True) (detectParts x))
    test "fromEither (Bifunctor.bimap (((==) 1) . ((flip mod) 2) . length) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap (((==) 1) . ((flip mod) 2) . length) (const True) (detectParts x))

    putStrLn "\n============ Show (Bipartite.AdjacencyMap.Algorithm.Matching a b) ============"
    test "show (matching [])                == \"matching []\"" $
          show (matching [] :: MII)         ==  "matching []"
    test "show (matching [(2,'a'),(1,'b')]) == \"matching [(1,'b'),(2,'a')]\"" $
          show (matching [(2,'a'),(1,'b')] :: MIC) == "matching [(1,'b'),(2,'a')]"

    putStrLn "\n============ Eq (Bipartite.AdjacencyMap.Algorithm.Matching a b) ============"
    test "(x == y) == ((pairOfLeft x == pairOfLeft y) && (pairOfRight x == pairOfRight y))" $ \(x :: MII) (y :: MII) ->
        (x == y) == ((pairOfLeft x == pairOfLeft y) && (pairOfRight x == pairOfRight y))

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.pairOfLeft ============"
    test "pairOfLeft (matching [])                 == Map.empty" $
          pairOfLeft (matching [] :: MII)          == Map.empty
    test "pairOfLeft (matching [(2,'a'), (1,'b')]) == Map.fromList [(2,'a'), (1,'b')]" $
          pairOfLeft (matching [(2,'a'), (1,'b')] :: MIC) == Map.fromList [(2,'a'), (1,'b')]
    test "Map.size . pairOfLeft                    == Map.size . pairOfRight" $ \(x :: MII) ->
         (Map.size . pairOfLeft) x                 ==(Map.size . pairOfRight) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.pairOfRight ============"
    test "pairOfRight (matching [])                 == Map.empty" $
          pairOfRight (matching [] :: MII)          == Map.empty
    test "pairOfRight (matching [(2,'a'), (1,'b')]) == Map.fromList [('a',2), ('b',1)]" $
          pairOfRight (matching [(2,'a'), (1,'b')] :: MIC) == Map.fromList [('a',2), ('b',1)]
    test "Map.size . pairOfRight                    == Map.size . pairOfLeft" $ \(x :: MII) ->
         (Map.size . pairOfRight) x                 ==(Map.size . pairOfLeft) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.matching ============"
    test "matching [(1,'a'), (1,'b')]                   == matching [(1,'b')]" $
          matching [(1,'a'), (1,'b')]                   == (matching [(1,'b')] :: MIC)
    test "matching [(1,'a'), (1,'b'), (2,'b'), (2,'a')] == matching [(2,'a')]" $
          matching [(1,'a'), (1,'b'), (2,'b'), (2,'a')] == (matching [(2,'a')] :: MIC)

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isMatchingOf ============"
    test "isMatchingOf (matching []) x               == True" $ \(x :: BAII) ->
          isMatchingOf (matching []) x               == True
    test "isMatchingOf (matching xs) empty           == null xs" $ \(xs :: [(Int, Int)]) ->
          isMatchingOf (matching xs) empty           == null xs
    test "isMatchingOf (matching [(x,y)]) (edge x y) == True" $ \(x :: Int) (y :: Int) ->
          isMatchingOf (matching [(x,y)]) (edge x y) == True
    test "isMatchingOf (matching [(1,2)]) (edge 2 1) == False" $
          isMatchingOf (matching [(1,2)]) (edge 2 1 :: BAII) == False

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.matchingSize ============"
    test "matchingSize (matching [])                 == 0" $
          matchingSize (matching [] :: MII)          == 0
    test "matchingSize (matching [(2,'a'), (1,'b')]) == 2" $
          matchingSize (matching [(2,'a'), (1,'b')] :: MIC) == 2
    test "matchingSize (matching [(1,'a'), (1,'b')]) == 1" $
          matchingSize (matching [(1,'a'), (1,'b')] :: MIC) == 1
    test "matchingSize (matching xs)                 <= length xs" $ \(xs :: [(Int, Int)]) ->
          matchingSize (matching xs)                 <= length xs
    test "matchingSize x                             == Map.size . pairOfLeft" $ \(x :: MII) ->
          matchingSize x                             ==(Map.size . pairOfLeft) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.maxMatching ============"
    test "maxMatching empty                                          == matching []" $
          maxMatching (empty :: BAII)                                == matching []
    test "maxMatching (vertices xs ys)                               == matching []" $ \(xs :: [Int]) (ys :: [Int]) ->
          maxMatching (vertices xs ys)                               == matching []
    test "maxMatching (path [1,2,3,4])                               == matching [(1,2), (3,4)]" $
          maxMatching (path ([1,2,3,4] :: LII))                      == matching [(1,2), (3,4)]
    test "matchingSize (maxMatching (circuit [(1,2), (3,4), (5,6)])) == 3" $
          matchingSize (maxMatching (circuit [(1,2), (3,4), (5,6)] :: BAII)) == 3
    test "matchingSize (maxMatching (star x (y:ys)))                 == 1" $ \(x :: Int) (y :: Int) (ys :: [Int]) ->
          matchingSize (maxMatching (star x (y:ys)))                 == 1
    test "matchingSize (maxMatching (biclique xs ys))                == min (length (nub xs)) (length (nub ys))" $ \(xs :: [Int]) (ys :: [Int]) ->
          matchingSize (maxMatching (biclique xs ys))                == min (length (nub xs)) (length (nub ys))
    test "isMatchingOf (maxMatching x) x                             == True" $ \(x :: BAII) ->
          isMatchingOf (maxMatching x) x                             == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isVertexCoverOf ============"
    test "isVertexCoverOf (xs             , ys             ) empty          == Set.null xs && Set.null ys" $ \(xs :: Set Int) (ys :: Set Int) ->
          isVertexCoverOf (xs             , ys             ) empty          ==(Set.null xs && Set.null ys)
    test "isVertexCoverOf (xs             , ys             ) (leftVertex x) == Set.isSubsetOf xs (Set.singleton x) && Set.null ys" $ \(x :: Int) (xs :: Set Int) (ys :: Set Int) ->
          isVertexCoverOf (xs             , ys             ) (leftVertex x) ==(Set.isSubsetOf xs (Set.singleton x) && Set.null ys)
    test "isVertexCoverOf (Set.empty      , Set.empty      ) (edge x y)     == False" $ \(x :: Int) (y :: Int) ->
          isVertexCoverOf (Set.empty      , Set.empty      ) (edge x y)     == False
    test "isVertexCoverOf (Set.singleton x, ys             ) (edge x y)     == Set.isSubsetOf ys (Set.singleton y)" $ \(x :: Int) (y :: Int) (ys :: Set Int) ->
          isVertexCoverOf (Set.singleton x, ys             ) (edge x y)     == Set.isSubsetOf ys (Set.singleton y)
    test "isVertexCoverOf (xs             , Set.singleton y) (edge x y)     == Set.isSubsetOf xs (Set.singleton x)" $ \(x :: Int) (y :: Int) (xs :: Set Int) ->
          isVertexCoverOf (xs             , Set.singleton y) (edge x y)     == Set.isSubsetOf xs (Set.singleton x)

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.minVertexCover ============"
    test "minVertexCover empty                              == (Set.empty, Set.empty)" $
          minVertexCover (empty :: BAII)                    == (Set.empty, Set.empty)
    test "minVertexCover (vertices xs ys)                   == (Set.empty, Set.empty)" $ \(xs :: [Int]) (ys :: [Int]) ->
          minVertexCover (vertices xs ys)                   == (Set.empty, Set.empty)
    test "minVertexCover (path [1,2,3])                     == (Set.empty, Set.singleton 2)" $
          minVertexCover (path [1,2,3] :: BAII)             == (Set.empty, Set.singleton 2)
    test "minVertexCover (star x (1:2:ys))                  == (Set.singleton x, Set.empty)" $ \(x :: Int) (ys :: [Int]) ->
          minVertexCover (star x (1:2:ys) :: BAII)          == (Set.singleton x, Set.empty)
    test "vertexCoverSize (minVertexCover (biclique xs ys)) == min (length (nub xs)) (length (nub ys))" $ size10 $ \(xs :: [Int]) (ys :: [Int]) ->
          vertexCoverSize (minVertexCover (biclique xs ys)) == min (length (nub xs)) (length (nub ys))
    test "vertexCoverSize . minVertexCover                  == matchingSize . maxMatching" $ \(x :: BAII) ->
         (vertexCoverSize . minVertexCover) x               ==(matchingSize . maxMatching) x
    test "isVertexCoverOf (minVertexCover x) x              == True" $ \(x :: BAII) ->
          isVertexCoverOf (minVertexCover x) x              == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isIndependentSetOf ============"
    test "isIndependentSetOf (xs             , ys             ) empty          == Set.null xs && Set.null ys" $ \(xs :: Set Int) (ys :: Set Int) ->
          isIndependentSetOf (xs             , ys             ) empty          ==(Set.null xs && Set.null ys)
    test "isIndependentSetOf (xs             , ys             ) (leftVertex x) == Set.isSubsetOf xs (Set.singleton x) && Set.null ys" $ \(x :: Int) (xs :: Set Int) (ys :: Set Int) ->
          isIndependentSetOf (xs             , ys             ) (leftVertex x) ==(Set.isSubsetOf xs (Set.singleton x) && Set.null ys)
    test "isIndependentSetOf (Set.empty      , Set.empty      ) (edge x y)     == True" $ \(x :: Int) (y :: Int) ->
          isIndependentSetOf (Set.empty      , Set.empty      ) (edge x y)     == True
    test "isIndependentSetOf (Set.singleton x, ys             ) (edge x y)     == Set.null ys" $ \(x :: Int) (y :: Int) (ys :: Set Int) ->
          isIndependentSetOf (Set.singleton x, ys             ) (edge x y)     == Set.null ys
    test "isIndependentSetOf (xs             , Set.singleton y) (edge x y)     == Set.null xs" $ \(x :: Int) (y :: Int) (xs :: Set Int) ->
          isIndependentSetOf (xs             , Set.singleton y) (edge x y)     == Set.null xs

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.maxIndependentSet ============"
    test "maxIndependentSet empty                                 == (Set.empty, Set.empty)" $
          maxIndependentSet (empty :: BAII)                       == (Set.empty, Set.empty)
    test "maxIndependentSet (vertices xs ys)                      == (Set.fromList xs, Set.fromList ys)" $ \(xs :: [Int]) (ys :: [Int]) ->
          maxIndependentSet (vertices xs ys)                      == (Set.fromList xs, Set.fromList ys)
    test "maxIndependentSet (path [1,2,3])                        == (Set.fromList [1,3], Set.empty)" $
          maxIndependentSet (path [1,2,3] :: BAII)                == (Set.fromList [1,3], Set.empty)
    test "maxIndependentSet (star x (1:2:ys))                     == (Set.empty, Set.fromList (1:2:ys))" $ \(x :: Int) (ys :: [Int]) ->
          maxIndependentSet (star x (1:2:ys))                     == (Set.empty, Set.fromList (1:2:ys))
    test "independentSetSize (maxIndependentSet (biclique xs ys)) == max (length (nub xs)) (length (nub ys))" $ \(xs :: [Int]) (ys :: [Int]) ->
          independentSetSize (maxIndependentSet (biclique xs ys)) == max (length (nub xs)) (length (nub ys))
    test "independentSetSize (maxIndependentSet x)                == vertexCount x - vertexCoverSize (minVertexCover x)" $ \(x :: BAII) ->
          independentSetSize (maxIndependentSet x)                == vertexCount x - vertexCoverSize (minVertexCover x)
    test "isIndependentSetOf (maxIndependentSet x) x              == True" $ \(x :: BAII) ->
          isIndependentSetOf (maxIndependentSet x) x              == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.augmentingPath ============"
    test "augmentingPath (matching [])      empty            == Left (Set.empty, Set.empty)" $
          augmentingPath (matching [])     (empty :: BAII)   == Left (Set.empty, Set.empty)
    test "augmentingPath (matching [])      (edge 1 2)       == Right [1,2]" $
          augmentingPath (matching [])      (edge 1 2)       == Right ([1,2] :: LII)
    test "augmentingPath (matching [(1,2)]) (path [1,2,3])   == Left (Set.empty, Set.singleton 2)" $
          augmentingPath (matching [(1,2)]) (path [1,2,3] :: BAII) == Left (Set.empty, Set.singleton 2)
    test "augmentingPath (matching [(3,2)]) (path [1,2,3,4]) == Right [1,2,3,4]" $
          augmentingPath (matching [(3,2)]) (path [1,2,3,4]) == Right ([1,2,3,4] :: LII)
    test "isLeft (augmentingPath (maxMatching x) x)          == True" $ \(x :: BAII) ->
          isLeft (augmentingPath (maxMatching x) x)          == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.consistentMatching ============"
    test "consistentMatching (matching xs)   == True" $ \(xs :: [(Int,Int)]) ->
          consistentMatching (matching xs)   == True
    test "consistentMatching (maxMatching x) == True" $ \(x :: BAII) ->
          consistentMatching (maxMatching x) == True
testBipartiteAdjacencyMapAlgorithm :: IO ()
testBipartiteAdjacencyMapAlgorithm = do
    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.detectParts ============"
    test "detectParts empty                                       == Right empty" $
          detectParts (AM.empty :: AI)                            == Right empty
    test "detectParts (vertex 1)                                  == Right (leftVertex 1)" $
          detectParts (AM.vertex 1 :: AI)                         == Right (leftVertex 1)
    test "detectParts (edge 1 1)                                  == Left [1]" $
          detectParts (AM.edge 1 1 :: AI)                         == Left [1]
    test "detectParts (edge 1 2)                                  == Right (edge 1 2)" $
          detectParts (AM.edge 1 2 :: AI)                         == Right (edge 1 2)
    test "detectParts (edge 0 (-1))                               == Right (edge (-1) 0)" $
          detectParts (AM.edge 0 (-1) :: AI)                      == Right (edge (-1) 0)
    test "detectParts (1 * (2 + 3))                               == Right (edges [(1, 2), (1, 3)])" $
          detectParts (1 * (2 + 3) :: AI)                         == Right (edges [(1, 2), (1, 3)])
    test "detectParts ((1 + 3) * (2 + 4) + 6 * 5)                 == Right (swap (1 + 3) * (2 + 4) + swap 5 * 6" $
          detectParts ((1 + 3) * (2 + 4) + 6 * 5 :: AI)           == Right (swap (1 + 3) * (2 * 4) + swap 5 * 6)
    test "detectParts ((1 + 2) * (3 + 4) * (5 + 6))               == Left [1, 3, 2, 4, 5]" $
          detectParts ((1 + 2) * (3 + 4) * (5 + 6) :: AI)         == Left [1, 3, 2, 4, 5]
    test "detectParts ((1 + 2) * (3 + 4) + (3 + 4) * 5)           == Right (swap (1 + 2) * (3 + 4) + swap 5 * (3 + 4))" $
          detectParts ((1 + 2) * (3 + 4) + (3 + 4) * 5 :: AI)     == Right (swap (1 + 2) * (3 + 4) + swap 5 * (3 + 4))
    test "detectParts (1 * 2 * 3)                                 == Left [2, 3, 1]" $
          detectParts (1 * 2 * 3 :: AI)                           == Left [1, 2, 3]
    test "detectParts ((1 * 3 * 4) + 2 * (1 + 2))                 == Left [2]" $
          detectParts ((1 * 3 * 4) + 2 * (1 + 2) :: AI)           == Left [2]
    test "detectParts (clique [1..10])                            == Left [1, 2, 3]" $
          detectParts (AM.clique [1..10] :: AI)                   == Left [1, 2, 3]
    test "detectParts (circuit [1..11])                           == Left [1..11]" $
          detectParts (AM.circuit [1..11] :: AI)                  == Left [1..11]
    test "detectParts (circuit [1..10])                           == Right (circuit [(2 * x - 1, 2 * x) | x <- [1..5]])" $
          detectParts (AM.circuit [1..10] :: AI)                  == Right (circuit [(2 * x - 1, 2 * x) | x <- [1..5]])
    test "detectParts (biclique [] xs)                            == Right (vertices xs [])" $ \(xs :: [Int]) ->
          detectParts (AM.biclique [] xs :: AI)                   == Right (vertices xs [])
    test "detectParts (biclique (map Left (x:xs)) (map Right ys)) == Right (biclique (map Left (x:xs)) (map Right ys))" $ \(x :: Int) (xs :: [Int]) (ys :: [Int]) ->
          detectParts (AM.biclique (map Left (x:xs)) (map Right ys)) == Right (biclique (map Left (x:xs)) (map Right ys))
    test "isRight (detectParts (star x ys))                       == not (elem x ys)" $ \(x :: Int) (ys :: [Int]) ->
          isRight (detectParts (AM.star x ys))                    == (not $ elem x ys)
    test "isRight (detectParts (fromBipartite (toBipartite x)))   == True" $ \(x :: AII) ->
          isRight (detectParts (fromBipartite (toBipartite x)))   == True

    -- TODO: Clean up these tests
    putStrLn ""
    test "((all ((flip Set.member) $ edgeSet $ symmetricClosure x) . edgeSet) <$> detectParts x) /= Right False" $ \(x :: AI) ->
          ((all ((flip Set.member) $ AM.edgeSet $ AM.symmetricClosure x) . edgeSet) <$> detectParts x) /= Right False
    test "(Set.map $ fromEither) <$> (vertexSet <$> (detectParts (fromBipartite (toBipartite x)))) == Right (vertexSet x)" $ \(x :: AII) ->
         ((Set.map $ fromEither) <$> (vertexSet <$> (detectParts (fromBipartite (toBipartite x))))) == Right (AM.vertexSet x)
    test "fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (vertexSet x) . Set.fromList) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (AM.vertexSet x) . Set.fromList) (const True) (detectParts x))
    test "fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (edgeSet (symmetricClosure x)) . AM.edgeSet . circuit) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (AM.edgeSet (AM.symmetricClosure x)) . AM.edgeSet . AM.circuit) (const True) (detectParts x))
    test "fromEither (Bifunctor.bimap (((==) 1) . ((flip mod) 2) . length) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap (((==) 1) . ((flip mod) 2) . length) (const True) (detectParts x))

    putStrLn "\n============ Show (Bipartite.AdjacencyMap.Algorithm.Matching a b) ============"
    test "show (matching [])                == \"matching []\"" $
          show (matching [] :: MII)         ==  "matching []"
    test "show (matching [(2,'a'),(1,'b')]) == \"matching [(1,'b'),(2,'a')]\"" $
          show (matching [(2,'a'),(1,'b')] :: MIC) == "matching [(1,'b'),(2,'a')]"

    putStrLn "\n============ Eq (Bipartite.AdjacencyMap.Algorithm.Matching a b) ============"
    test "(x == y) == ((pairOfLeft x == pairOfLeft y) && (pairOfRight x == pairOfRight y))" $ \(x :: MII) (y :: MII) ->
        (x == y) == ((pairOfLeft x == pairOfLeft y) && (pairOfRight x == pairOfRight y))

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.pairOfLeft ============"
    test "pairOfLeft (matching [])                 == Map.empty" $
          pairOfLeft (matching [] :: MII)          == Map.empty
    test "pairOfLeft (matching [(2,'a'), (1,'b')]) == Map.fromList [(2,'a'), (1,'b')]" $
          pairOfLeft (matching [(2,'a'), (1,'b')] :: MIC) == Map.fromList [(2,'a'), (1,'b')]
    test "Map.size . pairOfLeft                    == Map.size . pairOfRight" $ \(x :: MII) ->
         (Map.size . pairOfLeft) x                 ==(Map.size . pairOfRight) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.pairOfRight ============"
    test "pairOfRight (matching [])                 == Map.empty" $
          pairOfRight (matching [] :: MII)          == Map.empty
    test "pairOfRight (matching [(2,'a'), (1,'b')]) == Map.fromList [('a',2), ('b',1)]" $
          pairOfRight (matching [(2,'a'), (1,'b')] :: MIC) == Map.fromList [('a',2), ('b',1)]
    test "Map.size . pairOfRight                    == Map.size . pairOfLeft" $ \(x :: MII) ->
         (Map.size . pairOfRight) x                 ==(Map.size . pairOfLeft) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.matching ============"
    test "matching [(1,'a'), (1,'b')]                   == matching [(1,'b')]" $
          matching [(1,'a'), (1,'b')]                   == (matching [(1,'b')] :: MIC)
    test "matching [(1,'a'), (1,'b'), (2,'b'), (2,'a')] == matching [(2,'a')]" $
          matching [(1,'a'), (1,'b'), (2,'b'), (2,'a')] == (matching [(2,'a')] :: MIC)

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isMatchingOf ============"
    test "isMatchingOf (matching []) x               == True" $ \(x :: BAII) ->
          isMatchingOf (matching []) x               == True
    test "isMatchingOf (matching xs) empty           == null xs" $ \(xs :: [(Int, Int)]) ->
          isMatchingOf (matching xs) empty           == null xs
    test "isMatchingOf (matching [(x,y)]) (edge x y) == True" $ \(x :: Int) (y :: Int) ->
          isMatchingOf (matching [(x,y)]) (edge x y) == True
    test "isMatchingOf (matching [(1,2)]) (edge 2 1) == False" $
          isMatchingOf (matching [(1,2)]) (edge 2 1 :: BAII) == False

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.matchingSize ============"
    test "matchingSize (matching [])                 == 0" $
          matchingSize (matching [] :: MII)          == 0
    test "matchingSize (matching [(2,'a'), (1,'b')]) == 2" $
          matchingSize (matching [(2,'a'), (1,'b')] :: MIC) == 2
    test "matchingSize (matching [(1,'a'), (1,'b')]) == 1" $
          matchingSize (matching [(1,'a'), (1,'b')] :: MIC) == 1
    test "matchingSize (matching xs)                 <= length xs" $ \(xs :: [(Int, Int)]) ->
          matchingSize (matching xs)                 <= length xs
    test "matchingSize x                             == Map.size . pairOfLeft" $ \(x :: MII) ->
          matchingSize x                             ==(Map.size . pairOfLeft) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.maxMatching ============"
    test "maxMatching empty                                          == matching []" $
          maxMatching (empty :: BAII)                                == matching []
    test "maxMatching (vertices xs ys)                               == matching []" $ \(xs :: [Int]) (ys :: [Int]) ->
          maxMatching (vertices xs ys)                               == matching []
    test "maxMatching (path [1,2,3,4])                               == matching [(1,2), (3,4)]" $
          maxMatching (path ([1,2,3,4] :: LII))                      == matching [(1,2), (3,4)]
    test "matchingSize (maxMatching (circuit [(1,2), (3,4), (5,6)])) == 3" $
          matchingSize (maxMatching (circuit [(1,2), (3,4), (5,6)] :: BAII)) == 3
    test "matchingSize (maxMatching (star x (y:ys)))                 == 1" $ \(x :: Int) (y :: Int) (ys :: [Int]) ->
          matchingSize (maxMatching (star x (y:ys)))                 == 1
    test "matchingSize (maxMatching (biclique xs ys))                == min (length (nub xs)) (length (nub ys))" $ \(xs :: [Int]) (ys :: [Int]) ->
          matchingSize (maxMatching (biclique xs ys))                == min (length (nub xs)) (length (nub ys))
    test "isMatchingOf (maxMatching x) x                             == True" $ \(x :: BAII) ->
          isMatchingOf (maxMatching x) x                             == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isVertexCoverOf ============"
    test "isVertexCoverOf (xs             , ys             ) empty          == Set.null xs && Set.null ys" $ \(xs :: Set Int) (ys :: Set Int) ->
          isVertexCoverOf (xs             , ys             ) empty          ==(Set.null xs && Set.null ys)
    test "isVertexCoverOf (xs             , ys             ) (leftVertex x) == Set.isSubsetOf xs (Set.singleton x) && Set.null ys" $ \(x :: Int) (xs :: Set Int) (ys :: Set Int) ->
          isVertexCoverOf (xs             , ys             ) (leftVertex x) ==(Set.isSubsetOf xs (Set.singleton x) && Set.null ys)
    test "isVertexCoverOf (Set.empty      , Set.empty      ) (edge x y)     == False" $ \(x :: Int) (y :: Int) ->
          isVertexCoverOf (Set.empty      , Set.empty      ) (edge x y)     == False
    test "isVertexCoverOf (Set.singleton x, ys             ) (edge x y)     == Set.isSubsetOf ys (Set.singleton y)" $ \(x :: Int) (y :: Int) (ys :: Set Int) ->
          isVertexCoverOf (Set.singleton x, ys             ) (edge x y)     == Set.isSubsetOf ys (Set.singleton y)
    test "isVertexCoverOf (xs             , Set.singleton y) (edge x y)     == Set.isSubsetOf xs (Set.singleton x)" $ \(x :: Int) (y :: Int) (xs :: Set Int) ->
          isVertexCoverOf (xs             , Set.singleton y) (edge x y)     == Set.isSubsetOf xs (Set.singleton x)

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.minVertexCover ============"
    test "minVertexCover empty                              == (Set.empty, Set.empty)" $
          minVertexCover (empty :: BAII)                    == (Set.empty, Set.empty)
    test "minVertexCover (vertices xs ys)                   == (Set.empty, Set.empty)" $ \(xs :: [Int]) (ys :: [Int]) ->
          minVertexCover (vertices xs ys)                   == (Set.empty, Set.empty)
    test "minVertexCover (path [1,2,3])                     == (Set.empty, Set.singleton 2)" $
          minVertexCover (path [1,2,3] :: BAII)             == (Set.empty, Set.singleton 2)
    test "minVertexCover (star x (1:2:ys))                  == (Set.singleton x, Set.empty)" $ \(x :: Int) (ys :: [Int]) ->
          minVertexCover (star x (1:2:ys) :: BAII)          == (Set.singleton x, Set.empty)
    test "vertexCoverSize (minVertexCover (biclique xs ys)) == min (length (nub xs)) (length (nub ys))" $ size10 $ \(xs :: [Int]) (ys :: [Int]) ->
          vertexCoverSize (minVertexCover (biclique xs ys)) == min (length (nub xs)) (length (nub ys))
    test "vertexCoverSize . minVertexCover                  == matchingSize . maxMatching" $ \(x :: BAII) ->
         (vertexCoverSize . minVertexCover) x               ==(matchingSize . maxMatching) x
    test "isVertexCoverOf (minVertexCover x) x              == True" $ \(x :: BAII) ->
          isVertexCoverOf (minVertexCover x) x              == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isIndependentSetOf ============"
    test "isIndependentSetOf (xs             , ys             ) empty          == Set.null xs && Set.null ys" $ \(xs :: Set Int) (ys :: Set Int) ->
          isIndependentSetOf (xs             , ys             ) empty          ==(Set.null xs && Set.null ys)
    test "isIndependentSetOf (xs             , ys             ) (leftVertex x) == Set.isSubsetOf xs (Set.singleton x) && Set.null ys" $ \(x :: Int) (xs :: Set Int) (ys :: Set Int) ->
          isIndependentSetOf (xs             , ys             ) (leftVertex x) ==(Set.isSubsetOf xs (Set.singleton x) && Set.null ys)
    test "isIndependentSetOf (Set.empty      , Set.empty      ) (edge x y)     == True" $ \(x :: Int) (y :: Int) ->
          isIndependentSetOf (Set.empty      , Set.empty      ) (edge x y)     == True
    test "isIndependentSetOf (Set.singleton x, ys             ) (edge x y)     == Set.null ys" $ \(x :: Int) (y :: Int) (ys :: Set Int) ->
          isIndependentSetOf (Set.singleton x, ys             ) (edge x y)     == Set.null ys
    test "isIndependentSetOf (xs             , Set.singleton y) (edge x y)     == Set.null xs" $ \(x :: Int) (y :: Int) (xs :: Set Int) ->
          isIndependentSetOf (xs             , Set.singleton y) (edge x y)     == Set.null xs

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.maxIndependentSet ============"
    test "maxIndependentSet empty                                 == (Set.empty, Set.empty)" $
          maxIndependentSet (empty :: BAII)                       == (Set.empty, Set.empty)
    test "maxIndependentSet (vertices xs ys)                      == (Set.fromList xs, Set.fromList ys)" $ \(xs :: [Int]) (ys :: [Int]) ->
          maxIndependentSet (vertices xs ys)                      == (Set.fromList xs, Set.fromList ys)
    test "maxIndependentSet (path [1,2,3])                        == (Set.fromList [1,3], Set.empty)" $
          maxIndependentSet (path [1,2,3] :: BAII)                == (Set.fromList [1,3], Set.empty)
    test "maxIndependentSet (star x (1:2:ys))                     == (Set.empty, Set.fromList (1:2:ys))" $ \(x :: Int) (ys :: [Int]) ->
          maxIndependentSet (star x (1:2:ys))                     == (Set.empty, Set.fromList (1:2:ys))
    test "independentSetSize (maxIndependentSet (biclique xs ys)) == max (length (nub xs)) (length (nub ys))" $ \(xs :: [Int]) (ys :: [Int]) ->
          independentSetSize (maxIndependentSet (biclique xs ys)) == max (length (nub xs)) (length (nub ys))
    test "independentSetSize (maxIndependentSet x)                == vertexCount x - vertexCoverSize (minVertexCover x)" $ \(x :: BAII) ->
          independentSetSize (maxIndependentSet x)                == vertexCount x - vertexCoverSize (minVertexCover x)
    test "isIndependentSetOf (maxIndependentSet x) x              == True" $ \(x :: BAII) ->
          isIndependentSetOf (maxIndependentSet x) x              == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.augmentingPath ============"
    test "augmentingPath (matching [])      empty            == Left (Set.empty, Set.empty)" $
          augmentingPath (matching [])     (empty :: BAII)   == Left (Set.empty, Set.empty)
    test "augmentingPath (matching [])      (edge 1 2)       == Right [1,2]" $
          augmentingPath (matching [])      (edge 1 2)       == Right ([1,2] :: LII)
    test "augmentingPath (matching [(1,2)]) (path [1,2,3])   == Left (Set.empty, Set.singleton 2)" $
          augmentingPath (matching [(1,2)]) (path [1,2,3] :: BAII) == Left (Set.empty, Set.singleton 2)
    test "augmentingPath (matching [(3,2)]) (path [1,2,3,4]) == Right [1,2,3,4]" $
          augmentingPath (matching [(3,2)]) (path [1,2,3,4]) == Right ([1,2,3,4] :: LII)
    test "isLeft (augmentingPath (maxMatching x) x)          == True" $ \(x :: BAII) ->
          isLeft (augmentingPath (maxMatching x) x)          == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.consistentMatching ============"
    test "consistentMatching (matching xs)   == True" $ \(xs :: [(Int,Int)]) ->
          consistentMatching (matching xs)   == True
    test "consistentMatching (maxMatching x) == True" $ \(x :: BAII) ->
          consistentMatching (maxMatching x) == True
testBipartiteAdjacencyMapAlgorithm = do
    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.detectParts ============"
    test "detectParts empty                                       == Right empty" $
          detectParts (AM.empty :: AI)                            == Right empty
    test "detectParts (vertex 1)                                  == Right (leftVertex 1)" $
          detectParts (AM.vertex 1 :: AI)                         == Right (leftVertex 1)
    test "detectParts (edge 1 1)                                  == Left [1]" $
          detectParts (AM.edge 1 1 :: AI)                         == Left [1]
    test "detectParts (edge 1 2)                                  == Right (edge 1 2)" $
          detectParts (AM.edge 1 2 :: AI)                         == Right (edge 1 2)
    test "detectParts (edge 0 (-1))                               == Right (edge (-1) 0)" $
          detectParts (AM.edge 0 (-1) :: AI)                      == Right (edge (-1) 0)
    test "detectParts (1 * (2 + 3))                               == Right (edges [(1, 2), (1, 3)])" $
          detectParts (1 * (2 + 3) :: AI)                         == Right (edges [(1, 2), (1, 3)])
    test "detectParts ((1 + 3) * (2 + 4) + 6 * 5)                 == Right (swap (1 + 3) * (2 + 4) + swap 5 * 6" $
          detectParts ((1 + 3) * (2 + 4) + 6 * 5 :: AI)           == Right (swap (1 + 3) * (2 * 4) + swap 5 * 6)
    test "detectParts ((1 + 2) * (3 + 4) * (5 + 6))               == Left [1, 3, 2, 4, 5]" $
          detectParts ((1 + 2) * (3 + 4) * (5 + 6) :: AI)         == Left [1, 3, 2, 4, 5]
    test "detectParts ((1 + 2) * (3 + 4) + (3 + 4) * 5)           == Right (swap (1 + 2) * (3 + 4) + swap 5 * (3 + 4))" $
          detectParts ((1 + 2) * (3 + 4) + (3 + 4) * 5 :: AI)     == Right (swap (1 + 2) * (3 + 4) + swap 5 * (3 + 4))
    test "detectParts (1 * 2 * 3)                                 == Left [2, 3, 1]" $
          detectParts (1 * 2 * 3 :: AI)                           == Left [1, 2, 3]
    test "detectParts ((1 * 3 * 4) + 2 * (1 + 2))                 == Left [2]" $
          detectParts ((1 * 3 * 4) + 2 * (1 + 2) :: AI)           == Left [2]
    test "detectParts (clique [1..10])                            == Left [1, 2, 3]" $
          detectParts (AM.clique [1..10] :: AI)                   == Left [1, 2, 3]
    test "detectParts (circuit [1..11])                           == Left [1..11]" $
          detectParts (AM.circuit [1..11] :: AI)                  == Left [1..11]
    test "detectParts (circuit [1..10])                           == Right (circuit [(2 * x - 1, 2 * x) | x <- [1..5]])" $
          detectParts (AM.circuit [1..10] :: AI)                  == Right (circuit [(2 * x - 1, 2 * x) | x <- [1..5]])
    test "detectParts (biclique [] xs)                            == Right (vertices xs [])" $ \(xs :: [Int]) ->
          detectParts (AM.biclique [] xs :: AI)                   == Right (vertices xs [])
    test "detectParts (biclique (map Left (x:xs)) (map Right ys)) == Right (biclique (map Left (x:xs)) (map Right ys))" $ \(x :: Int) (xs :: [Int]) (ys :: [Int]) ->
          detectParts (AM.biclique (map Left (x:xs)) (map Right ys)) == Right (biclique (map Left (x:xs)) (map Right ys))
    test "isRight (detectParts (star x ys))                       == not (elem x ys)" $ \(x :: Int) (ys :: [Int]) ->
          isRight (detectParts (AM.star x ys))                    == (not $ elem x ys)
    test "isRight (detectParts (fromBipartite (toBipartite x)))   == True" $ \(x :: AII) ->
          isRight (detectParts (fromBipartite (toBipartite x)))   == True

    -- TODO: Clean up these tests
    putStrLn ""
    test "((all ((flip Set.member) $ edgeSet $ symmetricClosure x) . edgeSet) <$> detectParts x) /= Right False" $ \(x :: AI) ->
          ((all ((flip Set.member) $ AM.edgeSet $ AM.symmetricClosure x) . edgeSet) <$> detectParts x) /= Right False
    test "(Set.map $ fromEither) <$> (vertexSet <$> (detectParts (fromBipartite (toBipartite x)))) == Right (vertexSet x)" $ \(x :: AII) ->
         ((Set.map $ fromEither) <$> (vertexSet <$> (detectParts (fromBipartite (toBipartite x))))) == Right (AM.vertexSet x)
    test "fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (vertexSet x) . Set.fromList) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (AM.vertexSet x) . Set.fromList) (const True) (detectParts x))
    test "fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (edgeSet (symmetricClosure x)) . AM.edgeSet . circuit) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap ((flip Set.isSubsetOf) (AM.edgeSet (AM.symmetricClosure x)) . AM.edgeSet . AM.circuit) (const True) (detectParts x))
    test "fromEither (Bifunctor.bimap (((==) 1) . ((flip mod) 2) . length) (const True) (detectParts x)) == True" $ \(x :: AI) ->
          fromEither (Bifunctor.bimap (((==) 1) . ((flip mod) 2) . length) (const True) (detectParts x))

    putStrLn "\n============ Show (Bipartite.AdjacencyMap.Algorithm.Matching a b) ============"
    test "show (matching [])                == \"matching []\"" $
          show (matching [] :: MII)         ==  "matching []"
    test "show (matching [(2,'a'),(1,'b')]) == \"matching [(1,'b'),(2,'a')]\"" $
          show (matching [(2,'a'),(1,'b')] :: MIC) == "matching [(1,'b'),(2,'a')]"

    putStrLn "\n============ Eq (Bipartite.AdjacencyMap.Algorithm.Matching a b) ============"
    test "(x == y) == ((pairOfLeft x == pairOfLeft y) && (pairOfRight x == pairOfRight y))" $ \(x :: MII) (y :: MII) ->
        (x == y) == ((pairOfLeft x == pairOfLeft y) && (pairOfRight x == pairOfRight y))

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.pairOfLeft ============"
    test "pairOfLeft (matching [])                 == Map.empty" $
          pairOfLeft (matching [] :: MII)          == Map.empty
    test "pairOfLeft (matching [(2,'a'), (1,'b')]) == Map.fromList [(2,'a'), (1,'b')]" $
          pairOfLeft (matching [(2,'a'), (1,'b')] :: MIC) == Map.fromList [(2,'a'), (1,'b')]
    test "Map.size . pairOfLeft                    == Map.size . pairOfRight" $ \(x :: MII) ->
         (Map.size . pairOfLeft) x                 ==(Map.size . pairOfRight) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.pairOfRight ============"
    test "pairOfRight (matching [])                 == Map.empty" $
          pairOfRight (matching [] :: MII)          == Map.empty
    test "pairOfRight (matching [(2,'a'), (1,'b')]) == Map.fromList [('a',2), ('b',1)]" $
          pairOfRight (matching [(2,'a'), (1,'b')] :: MIC) == Map.fromList [('a',2), ('b',1)]
    test "Map.size . pairOfRight                    == Map.size . pairOfLeft" $ \(x :: MII) ->
         (Map.size . pairOfRight) x                 ==(Map.size . pairOfLeft) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.matching ============"
    test "matching [(1,'a'), (1,'b')]                   == matching [(1,'b')]" $
          matching [(1,'a'), (1,'b')]                   == (matching [(1,'b')] :: MIC)
    test "matching [(1,'a'), (1,'b'), (2,'b'), (2,'a')] == matching [(2,'a')]" $
          matching [(1,'a'), (1,'b'), (2,'b'), (2,'a')] == (matching [(2,'a')] :: MIC)

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isMatchingOf ============"
    test "isMatchingOf (matching []) x               == True" $ \(x :: BAII) ->
          isMatchingOf (matching []) x               == True
    test "isMatchingOf (matching xs) empty           == null xs" $ \(xs :: [(Int, Int)]) ->
          isMatchingOf (matching xs) empty           == null xs
    test "isMatchingOf (matching [(x,y)]) (edge x y) == True" $ \(x :: Int) (y :: Int) ->
          isMatchingOf (matching [(x,y)]) (edge x y) == True
    test "isMatchingOf (matching [(1,2)]) (edge 2 1) == False" $
          isMatchingOf (matching [(1,2)]) (edge 2 1 :: BAII) == False

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.matchingSize ============"
    test "matchingSize (matching [])                 == 0" $
          matchingSize (matching [] :: MII)          == 0
    test "matchingSize (matching [(2,'a'), (1,'b')]) == 2" $
          matchingSize (matching [(2,'a'), (1,'b')] :: MIC) == 2
    test "matchingSize (matching [(1,'a'), (1,'b')]) == 1" $
          matchingSize (matching [(1,'a'), (1,'b')] :: MIC) == 1
    test "matchingSize (matching xs)                 <= length xs" $ \(xs :: [(Int, Int)]) ->
          matchingSize (matching xs)                 <= length xs
    test "matchingSize x                             == Map.size . pairOfLeft" $ \(x :: MII) ->
          matchingSize x                             ==(Map.size . pairOfLeft) x

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.maxMatching ============"
    test "maxMatching empty                                          == matching []" $
          maxMatching (empty :: BAII)                                == matching []
    test "maxMatching (vertices xs ys)                               == matching []" $ \(xs :: [Int]) (ys :: [Int]) ->
          maxMatching (vertices xs ys)                               == matching []
    test "maxMatching (path [1,2,3,4])                               == matching [(1,2), (3,4)]" $
          maxMatching (path ([1,2,3,4] :: LII))                      == matching [(1,2), (3,4)]
    test "matchingSize (maxMatching (circuit [(1,2), (3,4), (5,6)])) == 3" $
          matchingSize (maxMatching (circuit [(1,2), (3,4), (5,6)] :: BAII)) == 3
    test "matchingSize (maxMatching (star x (y:ys)))                 == 1" $ \(x :: Int) (y :: Int) (ys :: [Int]) ->
          matchingSize (maxMatching (star x (y:ys)))                 == 1
    test "matchingSize (maxMatching (biclique xs ys))                == min (length (nub xs)) (length (nub ys))" $ \(xs :: [Int]) (ys :: [Int]) ->
          matchingSize (maxMatching (biclique xs ys))                == min (length (nub xs)) (length (nub ys))
    test "isMatchingOf (maxMatching x) x                             == True" $ \(x :: BAII) ->
          isMatchingOf (maxMatching x) x                             == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isVertexCoverOf ============"
    test "isVertexCoverOf (xs             , ys             ) empty          == Set.null xs && Set.null ys" $ \(xs :: Set Int) (ys :: Set Int) ->
          isVertexCoverOf (xs             , ys             ) empty          ==(Set.null xs && Set.null ys)
    test "isVertexCoverOf (xs             , ys             ) (leftVertex x) == Set.isSubsetOf xs (Set.singleton x) && Set.null ys" $ \(x :: Int) (xs :: Set Int) (ys :: Set Int) ->
          isVertexCoverOf (xs             , ys             ) (leftVertex x) ==(Set.isSubsetOf xs (Set.singleton x) && Set.null ys)
    test "isVertexCoverOf (Set.empty      , Set.empty      ) (edge x y)     == False" $ \(x :: Int) (y :: Int) ->
          isVertexCoverOf (Set.empty      , Set.empty      ) (edge x y)     == False
    test "isVertexCoverOf (Set.singleton x, ys             ) (edge x y)     == Set.isSubsetOf ys (Set.singleton y)" $ \(x :: Int) (y :: Int) (ys :: Set Int) ->
          isVertexCoverOf (Set.singleton x, ys             ) (edge x y)     == Set.isSubsetOf ys (Set.singleton y)
    test "isVertexCoverOf (xs             , Set.singleton y) (edge x y)     == Set.isSubsetOf xs (Set.singleton x)" $ \(x :: Int) (y :: Int) (xs :: Set Int) ->
          isVertexCoverOf (xs             , Set.singleton y) (edge x y)     == Set.isSubsetOf xs (Set.singleton x)

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.minVertexCover ============"
    test "minVertexCover empty                              == (Set.empty, Set.empty)" $
          minVertexCover (empty :: BAII)                    == (Set.empty, Set.empty)
    test "minVertexCover (vertices xs ys)                   == (Set.empty, Set.empty)" $ \(xs :: [Int]) (ys :: [Int]) ->
          minVertexCover (vertices xs ys)                   == (Set.empty, Set.empty)
    test "minVertexCover (path [1,2,3])                     == (Set.empty, Set.singleton 2)" $
          minVertexCover (path [1,2,3] :: BAII)             == (Set.empty, Set.singleton 2)
    test "minVertexCover (star x (1:2:ys))                  == (Set.singleton x, Set.empty)" $ \(x :: Int) (ys :: [Int]) ->
          minVertexCover (star x (1:2:ys) :: BAII)          == (Set.singleton x, Set.empty)
    test "vertexCoverSize (minVertexCover (biclique xs ys)) == min (length (nub xs)) (length (nub ys))" $ size10 $ \(xs :: [Int]) (ys :: [Int]) ->
          vertexCoverSize (minVertexCover (biclique xs ys)) == min (length (nub xs)) (length (nub ys))
    test "vertexCoverSize . minVertexCover                  == matchingSize . maxMatching" $ \(x :: BAII) ->
         (vertexCoverSize . minVertexCover) x               ==(matchingSize . maxMatching) x
    test "isVertexCoverOf (minVertexCover x) x              == True" $ \(x :: BAII) ->
          isVertexCoverOf (minVertexCover x) x              == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.isIndependentSetOf ============"
    test "isIndependentSetOf (xs             , ys             ) empty          == Set.null xs && Set.null ys" $ \(xs :: Set Int) (ys :: Set Int) ->
          isIndependentSetOf (xs             , ys             ) empty          ==(Set.null xs && Set.null ys)
    test "isIndependentSetOf (xs             , ys             ) (leftVertex x) == Set.isSubsetOf xs (Set.singleton x) && Set.null ys" $ \(x :: Int) (xs :: Set Int) (ys :: Set Int) ->
          isIndependentSetOf (xs             , ys             ) (leftVertex x) ==(Set.isSubsetOf xs (Set.singleton x) && Set.null ys)
    test "isIndependentSetOf (Set.empty      , Set.empty      ) (edge x y)     == True" $ \(x :: Int) (y :: Int) ->
          isIndependentSetOf (Set.empty      , Set.empty      ) (edge x y)     == True
    test "isIndependentSetOf (Set.singleton x, ys             ) (edge x y)     == Set.null ys" $ \(x :: Int) (y :: Int) (ys :: Set Int) ->
          isIndependentSetOf (Set.singleton x, ys             ) (edge x y)     == Set.null ys
    test "isIndependentSetOf (xs             , Set.singleton y) (edge x y)     == Set.null xs" $ \(x :: Int) (y :: Int) (xs :: Set Int) ->
          isIndependentSetOf (xs             , Set.singleton y) (edge x y)     == Set.null xs

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.maxIndependentSet ============"
    test "maxIndependentSet empty                                 == (Set.empty, Set.empty)" $
          maxIndependentSet (empty :: BAII)                       == (Set.empty, Set.empty)
    test "maxIndependentSet (vertices xs ys)                      == (Set.fromList xs, Set.fromList ys)" $ \(xs :: [Int]) (ys :: [Int]) ->
          maxIndependentSet (vertices xs ys)                      == (Set.fromList xs, Set.fromList ys)
    test "maxIndependentSet (path [1,2,3])                        == (Set.fromList [1,3], Set.empty)" $
          maxIndependentSet (path [1,2,3] :: BAII)                == (Set.fromList [1,3], Set.empty)
    test "maxIndependentSet (star x (1:2:ys))                     == (Set.empty, Set.fromList (1:2:ys))" $ \(x :: Int) (ys :: [Int]) ->
          maxIndependentSet (star x (1:2:ys))                     == (Set.empty, Set.fromList (1:2:ys))
    test "independentSetSize (maxIndependentSet (biclique xs ys)) == max (length (nub xs)) (length (nub ys))" $ \(xs :: [Int]) (ys :: [Int]) ->
          independentSetSize (maxIndependentSet (biclique xs ys)) == max (length (nub xs)) (length (nub ys))
    test "independentSetSize (maxIndependentSet x)                == vertexCount x - vertexCoverSize (minVertexCover x)" $ \(x :: BAII) ->
          independentSetSize (maxIndependentSet x)                == vertexCount x - vertexCoverSize (minVertexCover x)
    test "isIndependentSetOf (maxIndependentSet x) x              == True" $ \(x :: BAII) ->
          isIndependentSetOf (maxIndependentSet x) x              == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.augmentingPath ============"
    test "augmentingPath (matching [])      empty            == Left (Set.empty, Set.empty)" $
          augmentingPath (matching [])     (empty :: BAII)   == Left (Set.empty, Set.empty)
    test "augmentingPath (matching [])      (edge 1 2)       == Right [1,2]" $
          augmentingPath (matching [])      (edge 1 2)       == Right ([1,2] :: LII)
    test "augmentingPath (matching [(1,2)]) (path [1,2,3])   == Left (Set.empty, Set.singleton 2)" $
          augmentingPath (matching [(1,2)]) (path [1,2,3] :: BAII) == Left (Set.empty, Set.singleton 2)
    test "augmentingPath (matching [(3,2)]) (path [1,2,3,4]) == Right [1,2,3,4]" $
          augmentingPath (matching [(3,2)]) (path [1,2,3,4]) == Right ([1,2,3,4] :: LII)
    test "isLeft (augmentingPath (maxMatching x) x)          == True" $ \(x :: BAII) ->
          isLeft (augmentingPath (maxMatching x) x)          == True

    putStrLn "\n============ Bipartite.AdjacencyMap.Algorithm.consistentMatching ============"
    test "consistentMatching (matching xs)   == True" $ \(xs :: [(Int,Int)]) ->
          consistentMatching (matching xs)   == True
    test "consistentMatching (maxMatching x) == True" $ \(x :: BAII) ->
          consistentMatching (maxMatching x) == True