2011-12-20 33 views
7

我正在使用Data.Graph图形模拟Haskell中的模拟。仿真仅限于我的图形模型的2D网格。下面网格上每个点上的一个节点将包含一个Maybe Molecule类型,因此可能存在一个分子或者没有分子。编辑/更新Haskell中的图形

1 - 2 - 3 
| | | 
4 - 5 - 6 
| | | 
7 - 8 - 9 

我已经建立了这种表示,但是当涉及到更新分子的位置时,我觉得我要解决这个问题很长的路要走。到目前为止,我所做的是将所有节点都删除到节点列表中。我写了一个函数来交换这个节点列表中的两个项目。但是现在当我把所有东西都拉回来时,我遇到了问题,因为要生成一个新图,我需要一个顶点列表,我可以从顶点Graph函数轻松获得这些顶点。但我也需要用边缘触摸的顶点列表来压缩。不幸的是,Data.Graph的边缘Graph函数返回一个类型为Edge的元组列表,尽管我可以编写一个函数来派生具有边缘到顶点的列表顶点,但它并不直接有助于生成图形。这样做似乎对我来说足够的工作,我想知道我是否错过了一个有一个Graph函数,它只是采取一个图形,并返回一个更新节点的图形?

回答

7

FGL有这个伟大的“上下文”机制,让你模式匹配的图形查询。你可以把它想象成拖拽一个选定的顶点,使它位于图的其余部分。这可以让您查看该顶点如何连接到图形的其余部分。

{-# LANGUAGE TupleSections #-} 
import Control.Applicative 
import Control.Arrow 
import Data.Graph.Inductive 

-- Example graph from SO question. 
graph :: Gr (Maybe Int)() 
graph = mkGraph (map (id&&&Just) [1,2,3,4,5,6,7,8,9]) 
       (map (\(x,y) -> (x,y,())) $ 
        concatMap gridNeighbors [1..9]) 
    where gridNeighbors n = map (n,) 
         . filter ((&&) <$> valid <*> not . boundary n) 
         $ [n-3,n-1,n+1,n+3] 
     valid x = x > 0 && x < 10 
     boundary n x = case n `rem` 3 of 
         0 -> x == n + 1 
         1 -> x == n - 1 
         _ -> False 

-- Swap the labels of nodes 4 and 7 
swapTest g = case match 4 g of 
       (Just c4, g') -> case match 7 g' of 
            (Just c7, g'') -> setLabel c4 (lab' c7) & 
                (setLabel c7 (lab' c4) & 
                g'') 
            _ -> error "No node 7!" 
       _ -> error "No node 4!" 
    where setLabel :: Context a b -> a -> Context a b 
     setLabel (inEdges, n, _, outEdges) l = (inEdges, n, l, outEdges) 

你可以尝试运行swapTest graph地看到,节点4和你的图7中的标签交换。

4

在这里使用图表是否有特殊原因?在我看来,这组边缘几乎是固定的,并且你的网格仅在分子的位置上有所不同。

为什么不直接使用数组或其他数据结构,让您专注于分子及其位置?例如:

import Data.Array 

data Molecule = H2O | CO2 | NH3 

type Grid = Array (Int, Int) (Maybe Molecule) 

-- creates an empty grid               
grid :: Int -> Int -> Grid 
grid m n = array ((0, 0), (m - 1, n - 1)) assocs 
    where 
    assocs = [((i, j), Nothing) | i <- [0 .. m - 1], j <- [0 .. n - 1]] 

-- swap the molecules at the specified indices         
swap :: (Int, Int) -> (Int, Int) -> Grid -> Grid 
swap (i, j) (u, v) grid = 
    grid // [((i, j), grid ! (u, v)), ((u, v), grid ! (i, j))] 

-- etc. 

(如果你有很好的理由来使用图表,我当然完全在这里行,在这种情况下,我道歉......)

+0

如果我使用图形,我可以看到相邻节点是否被其他分子占用以进行碰撞检测检查。 – mikeyP 2011-12-21 12:01:48

+0

@mikeyP但是你也可以用数组来做到这一点,不是吗? – 2011-12-21 13:12:48

+0

你是对的,在Graph下是一个数组。但是通过图形,我可以去除图形上的分子不能通过的区域。我看不出一个干净利落的方式来与阵列做到这一点。 – mikeyP 2011-12-21 13:49:33