Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Library for working with (potentially infinite) graphs defined by neighbor-list functions

Here's a pattern I've used countless times across a variety of programming languages:

  1. Encounter a problem which can be easily reduced to some graph algorithm.
  2. Define an adjacency function: outEdges :: MyNode -> [MyNode].
  3. Code up some general form of said graph algorithm which takes this function as its first argument.

As an example, consider this (purposefully inefficient) method for computing the edit distance between two words. We will count the least number of insertions and deletions necessary to transform one word into another via breadth first search.

import Data.List
import Data.Maybe

alphabet :: String
alphabet = ['a'..'z']

wordNeighbors :: String -> [String]
wordNeighbors word = deletions ++ insertions where
    insertions = [pre++[c]++suf | (pre,suf) <- splits, c <- alphabet]
    deletions =  [pre++suf      | (pre,_:suf) <- take (length word) splits]

    splits = zip (inits word) (tails word)

shortestDistance :: (Eq a,Hashable a)=> (a -> [a]) -> a -> a -> Maybe Int
shortestDistance edgeFunc source target =
    -- 8 lines of code where I do a breadth-first traversal,
    -- using a HashSet to track previously visited nodes;
    -- yawn...

editDistance :: String -> String -> Int
editDistance a b = fromJust $ shortestDistance wordNeighbors a b

main = print $ editDistance "cat" "can"  -- prints 2

The problem is, I'm getting awfully tired of step 3. (see shortestDistance above...)

I feel like I've written the same algorithms hundreds of times. I'd love it if I could instead just somehow utilize FGL or Data.Graph and be done with it, but as far as I can tell both ultimately require the construction of some sort of Graph data structure which is strict with respect to the set of all nodes. This is an issue because in many problems, the graph is infinite (such as in the example above).

I specifically ask about Haskell because Haskell has such a strong focus on combinators that I somehow expected many of these algorithms to already exist somewhere.


Addendum: Here are other examples of functions I frequently write besides shortest-path:

-- Useful for organizing the computation of a recursively-defined
-- property of the nodes in an acyclic graph, such as nimbers.
dfsPostOrder :: (v -> [v]) -> v -> [v]
dfsPostOrder adjFunc root = ...

-- Find all nodes connected in some manner to the root node.
-- In case I know the components are finite size, but am not sure
-- of a nice way to express their contents.
-- (Note: The API below is only good for undirected graphs)
getComponent :: (v -> [v]) -> v -> Set v
getComponent adjFunc root = ...

-- Lazily organize the graph into groups by their minimum distance
-- to any of the nodes in @roots@.
-- One could use this to help incrementalize parts of e.g. a Game
-- of Life or Kinetic Monte Carlo simulation by locating regions
-- invalidated by changes in the state.
groupsByProximity :: (v -> [v]) -> Set v -> [Set v]
groupsByProximity adjFunc roots = ...

TL;DR: Is there any general way to write algorithms that work on potentially infinite, potentially cyclic, directed graphs---such as one defined by an adjacency function (Node -> [Node] or Node -> [(Node, Weight)])?

like image 262
Exp HP Avatar asked Aug 20 '16 21:08

Exp HP


1 Answers

I think most "breadth-first" search algorithms are really some sort of "best-first" algorithm. That is, the search frontier is placed in a priority queue which determines the order in which the nodes are visited.

I found two packages which implement general best-first algorithms:

  • astar
  • monad-dijkstra

Both of these modules have very generic interfaces - i.e. you supply a neighbor function, an inter-node distance function and (in the case of A-star) a heuristic function.

With the appropriate choice of heuristic and distance functions you might be able to map your search into one of these algorithms. For instance, this patent describes a way of employing A-star to solve the edit distance problem.

like image 134
ErikR Avatar answered Oct 14 '22 20:10

ErikR