2013-12-02 22:46:14 +01:00
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
|
|
|
{-# LANGUAGE OverlappingInstances #-}
|
2013-12-03 01:39:24 +01:00
|
|
|
|
{-# LANGUAGE TypeOperators #-}
|
|
|
|
|
{-# LANGUAGE TypeSynonymInstances #-}
|
2013-11-27 13:17:21 +01:00
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
--
|
|
|
|
|
-- Module : DCB
|
|
|
|
|
-- Copyright :
|
|
|
|
|
-- License : AllRightsReserved
|
|
|
|
|
--
|
|
|
|
|
-- Maintainer :
|
|
|
|
|
-- Stability :
|
|
|
|
|
-- Portability :
|
|
|
|
|
--
|
|
|
|
|
-- |
|
|
|
|
|
--
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
module DCB where
|
2013-12-03 01:39:24 +01:00
|
|
|
|
import Util
|
2013-11-27 13:17:21 +01:00
|
|
|
|
|
2013-11-29 20:42:03 +01:00
|
|
|
|
import Prelude hiding ((++))
|
|
|
|
|
import qualified Prelude ((++))
|
2013-11-27 23:34:22 +01:00
|
|
|
|
|
2013-11-29 19:09:05 +01:00
|
|
|
|
import Control.Monad.Par
|
2013-11-29 20:42:03 +01:00
|
|
|
|
import Data.Array.Repa ((:.) (..), Array, (!), (*^), (++), (+^),
|
|
|
|
|
(-^), (/^))
|
|
|
|
|
import qualified Data.Array.Repa as A
|
2013-11-29 19:09:05 +01:00
|
|
|
|
import Data.Array.Repa.Index
|
2013-11-29 20:34:52 +01:00
|
|
|
|
import Data.Either
|
2013-11-29 19:09:05 +01:00
|
|
|
|
import Data.Int
|
2013-12-03 01:39:24 +01:00
|
|
|
|
import Data.Maybe
|
2013-12-01 16:55:32 +01:00
|
|
|
|
import qualified Data.Vector.Unboxed as V
|
|
|
|
|
import Debug.Trace
|
2013-11-27 13:17:21 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | a one-dimensional array
|
2013-11-29 15:30:09 +01:00
|
|
|
|
type Vector r e = Array r DIM1 e
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | a two-dimensional array
|
2013-11-29 15:30:09 +01:00
|
|
|
|
type Matrix r e = Array r DIM2 e
|
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | A 'Matrix' of attribute values assigned to a graph’s nodes.
|
|
|
|
|
-- Each row contains the corresponding node’s attribute values.
|
2013-11-29 15:30:09 +01:00
|
|
|
|
type Attr = Matrix A.U Double
|
2013-12-01 15:29:48 +01:00
|
|
|
|
-- | Adjacency-Matrix
|
2013-12-03 00:22:51 +01:00
|
|
|
|
type Adj = Matrix A.U Int8
|
2013-12-01 15:29:48 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | Matrix storing the extent of a 'Graph'’s constraints fulfillment.
|
|
|
|
|
-- It stores the minimum (zeroth column) and maximum (first column) value of all
|
|
|
|
|
-- the 'Graph'’s nodes per attribute.
|
|
|
|
|
-- The 'Vector' stores values of @1@ if the bounds are within the allowed range
|
|
|
|
|
-- ragarding the corresponding attribute, or @0@ if not.
|
2013-12-03 00:22:51 +01:00
|
|
|
|
type Constraints = (Vector A.U Int, Matrix A.U Double)
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | A 'Vector' of weights indicating how much divergence is allowed in which dimension.
|
|
|
|
|
-- Each dimension represents an attribute.
|
2013-11-29 15:54:36 +01:00
|
|
|
|
type MaxDivergence = Vector A.U Double
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | A graph’s density.
|
2013-11-29 15:30:09 +01:00
|
|
|
|
type Density = Double
|
2013-11-27 13:17:21 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | consists of a 'Vector' denoting which columns of the 'Matrix' represents which originating
|
|
|
|
|
-- column in the global adjancency-matrix, a 'Matrix' of 'Constraints' and a scalar denoting the graph’s 'Density'
|
2013-11-29 15:30:09 +01:00
|
|
|
|
type Graph = (Vector A.U Int, Constraints, Density)
|
2013-11-27 13:17:21 +01:00
|
|
|
|
|
2013-12-02 22:46:14 +01:00
|
|
|
|
instance Ord Graph where
|
|
|
|
|
(nodes, _, _) `compare` (nodes', _, _) = (A.size $ A.extent nodes) `compare` (A.size $ A.extent nodes')
|
|
|
|
|
|
2013-12-01 16:55:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
testAdj :: Adj
|
|
|
|
|
testAdj = A.fromListUnboxed (ix2 10 10) [0,1,1,1,0,0,1,0,0,1,{----}1,0,0,0,1,0,1,1,0,0,
|
|
|
|
|
1,0,0,1,0,0,0,1,0,1,{----}1,0,1,0,1,1,1,0,0,0,
|
|
|
|
|
0,1,0,1,0,0,1,1,0,0,{----}0,0,0,1,0,0,1,0,1,1,
|
|
|
|
|
1,1,0,1,1,1,0,0,1,0,{----}0,1,1,0,1,0,0,0,0,1,
|
|
|
|
|
0,0,0,0,0,1,1,0,0,1,{----}1,0,1,0,0,1,0,1,1,0]
|
|
|
|
|
testAttr :: Attr
|
2013-12-01 17:22:13 +01:00
|
|
|
|
testAttr = A.fromListUnboxed (ix2 10 5) [ 0.2, 1.3, -1.4, 0.3, 0.0,
|
|
|
|
|
-0.3, 33.0, 0.0, -2.3, 0.1,
|
|
|
|
|
-1.1,-12.0, 2.3, 1.1, 3.2,
|
|
|
|
|
0.1, 1.7, 3.1, 0.7, 2.5,
|
|
|
|
|
1.4, 35.1, -1.1, 1.6, 1.4,
|
|
|
|
|
0.5, 13.4, -0.4, 0.5, 2.3,
|
|
|
|
|
0.9, 13.6, 1.1, 0.1, 1.9,
|
|
|
|
|
1.2, 12.9, -0.5, -0.3, 3.3,
|
|
|
|
|
3.1, 2.4, -0.1, 0.7, 0.4,
|
|
|
|
|
2.6, -7.4, -0.4, 1.3, 1.2]
|
2013-12-01 16:55:32 +01:00
|
|
|
|
testDivergence :: MaxDivergence
|
2013-12-01 17:22:13 +01:00
|
|
|
|
testDivergence = A.fromListUnboxed (ix1 5) [3.0, 0.0, 300.0, 2.0, 10.0]
|
2013-12-01 16:55:32 +01:00
|
|
|
|
|
|
|
|
|
testDensity = 0.7::Density;
|
|
|
|
|
testReq = 3 ::Int
|
|
|
|
|
|
|
|
|
|
|
2013-12-01 15:29:48 +01:00
|
|
|
|
-- | calculates all possible additions to one Graph, yielding a list of valid expansions
|
|
|
|
|
-- i.e. constraint a == Just Constraints for all returned Graphs
|
2013-12-03 01:39:24 +01:00
|
|
|
|
expand :: Adj -> Attr -> Density -> MaxDivergence -> Int -> Graph -> [Graph]
|
|
|
|
|
expand adj attr d div req g@(ind,_,_) = catMaybes $ map
|
|
|
|
|
(addPoint adj attr d div req g)
|
|
|
|
|
(V.toList $ V.findIndices (==True) $ A.toUnboxed $ addablePoints adj g)
|
2013-11-29 15:54:36 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | Creates an adjacency matrix from the given adjacency matrix where all
|
|
|
|
|
-- edges are removed whose belonging nodes cannot fulfill the passed constraints.
|
|
|
|
|
-- Additionally, all pairs of connected nodes that satisfy the constraints are
|
|
|
|
|
-- returned as a 'Graph'.
|
|
|
|
|
preprocess :: Adj -- ^ original adjacency matrix
|
|
|
|
|
-> Attr -- ^ table of the node’s attributes
|
|
|
|
|
-> MaxDivergence -- ^ maximum allowed ranges of the node’s attribute
|
|
|
|
|
-- values to be considered as consistent
|
|
|
|
|
-> Int -- ^ required number of consistent attributes
|
|
|
|
|
-> (Adj, [Graph])
|
|
|
|
|
preprocess adj attr div req =
|
2013-11-29 20:34:52 +01:00
|
|
|
|
let
|
|
|
|
|
(Z:.nNodes:._) = A.extent adj
|
2013-12-01 16:55:32 +01:00
|
|
|
|
results = map (initGraph attr div req) [(i, j) | i <- [0..(nNodes-1)], j <- [(i+1)..(nNodes-1)], adj!(ix2 i j) /= 0]
|
2013-11-29 20:34:52 +01:00
|
|
|
|
finalGraphs = lefts results
|
2013-12-01 16:55:32 +01:00
|
|
|
|
mask = A.fromUnboxed (A.extent adj) $V.replicate (nNodes*nNodes) False V.//
|
|
|
|
|
((map (\(i,j) -> (i*nNodes + (mod j nNodes), True)) $rights results)
|
|
|
|
|
Prelude.++ (map (\(i,j) -> (j*nNodes + (mod i nNodes), True)) $rights results))
|
2013-11-29 20:34:52 +01:00
|
|
|
|
adj' = A.computeS $A.fromFunction (A.extent adj) (\sh -> if mask!sh then 0 else adj!sh)
|
|
|
|
|
in (adj', finalGraphs)
|
2013-11-29 19:09:05 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | Initializes a seed 'Graph' if it fulfills the constraints, returns the input nodes
|
|
|
|
|
-- otherwise. It is assumed that the given nodes are connected.
|
|
|
|
|
initGraph :: Attr -- ^ table of all node’s attributes
|
|
|
|
|
-> MaxDivergence
|
|
|
|
|
-> Int -- ^ required number of consistent attributes
|
|
|
|
|
-> (Int, Int) -- ^ nodes to create a seed 'Graph' of
|
|
|
|
|
-> Either Graph (Int, Int)
|
2013-11-29 20:34:52 +01:00
|
|
|
|
initGraph attr div req (i, j) =
|
2013-11-29 19:09:05 +01:00
|
|
|
|
let
|
|
|
|
|
constr = constraintInit attr div req i j
|
|
|
|
|
in case constr of
|
2013-11-29 20:34:52 +01:00
|
|
|
|
Nothing -> Right (i, j)
|
2013-12-02 22:56:30 +01:00
|
|
|
|
Just c -> Left (A.fromListUnboxed (ix1 2) [i,j], c, 1)
|
2013-11-29 19:09:05 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | checks constraints of an initializing seed and creates 'Constraints' matrix if the
|
|
|
|
|
-- check is positive
|
|
|
|
|
constraintInit :: Attr -> MaxDivergence -> Int -- ^ required number of consistent attributes
|
|
|
|
|
-> Int -- ^ first node to test
|
|
|
|
|
-> Int -- ^ second node to test first node against
|
|
|
|
|
-> Maybe Constraints
|
2013-11-29 19:09:05 +01:00
|
|
|
|
constraintInit attr div req i j =
|
|
|
|
|
let
|
|
|
|
|
(Z:._:.nAttr) = A.extent attr
|
|
|
|
|
fConstr (Z:.a:.c) =
|
|
|
|
|
let
|
|
|
|
|
col = A.slice attr (A.Any:.a)
|
|
|
|
|
in case c of
|
|
|
|
|
0 -> min (attr!(ix2 i a)) (attr!(ix2 j a))
|
|
|
|
|
1 -> max (attr!(ix2 i a)) (attr!(ix2 j a))
|
|
|
|
|
constr = A.computeS $A.fromFunction (ix2 nAttr 2) fConstr
|
|
|
|
|
fulfill = A.zipWith (\thediv dist -> if abs dist <= thediv then 1 else 0) div
|
|
|
|
|
$A.foldS (-) 0 constr
|
|
|
|
|
nrHit = A.foldAllS (+) (0::Int) $A.map fromIntegral fulfill
|
|
|
|
|
in if nrHit >= req then Just (A.computeS fulfill, constr) else Nothing
|
|
|
|
|
|
2013-12-01 15:29:48 +01:00
|
|
|
|
-- | removes all duplicate graphs
|
2013-11-29 15:54:36 +01:00
|
|
|
|
filterLayer :: Vector A.U Graph -> Vector A.U Graph
|
2013-11-29 19:09:05 +01:00
|
|
|
|
filterLayer gs = undefined -- TODO
|
2013-11-27 13:17:21 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- | Checks whether a given base 'Graph' can be extended by a single node and
|
|
|
|
|
-- the resulting 'Graph' still satisfies the given attribute constraints.
|
|
|
|
|
-- In case of a successful expansion the updated 'Constraints' matrix is returned.
|
|
|
|
|
constraint :: Attr -> MaxDivergence -> Int -- ^ required number of consistent attributes
|
|
|
|
|
-> Graph -- ^ base graph
|
|
|
|
|
-> Int -- ^ node to extend base graph by
|
|
|
|
|
-> Maybe Constraints
|
2013-11-29 19:09:05 +01:00
|
|
|
|
constraint attr div req (_, (fulfill, constr), _) newNode =
|
|
|
|
|
let
|
|
|
|
|
updateConstr :: (DIM2 -> Double) -> DIM2 -> Double
|
|
|
|
|
updateConstr f sh@(Z:._:.c) =
|
|
|
|
|
case c of
|
|
|
|
|
0 -> min (f sh) (attr!sh)
|
|
|
|
|
1 -> max (f sh) (attr!sh)
|
|
|
|
|
constrNew = A.computeUnboxedS $A.traverse constr id updateConstr
|
2013-12-03 00:22:51 +01:00
|
|
|
|
fulfillNew = A.zipWith (\i b -> if i == 1 && b then 1::Int else 0::Int) fulfill
|
2013-11-29 19:09:05 +01:00
|
|
|
|
$A.zipWith (\thediv dist -> abs dist <= thediv) div $A.foldS (-) 0 constrNew
|
|
|
|
|
nrHit = A.foldAllS (+) (0::Int) $A.map fromIntegral fulfillNew
|
|
|
|
|
in if nrHit >= req then Just (A.computeS fulfillNew, constrNew) else Nothing
|
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
-- updates the density of a graph extended by a single node
|
|
|
|
|
updateDensity :: Adj -- ^ global adjacency matrix of all nodes
|
|
|
|
|
-> Vector A.U Int -- ^ nodes of the base graph
|
|
|
|
|
-> Int -- ^ node to extend the graph by
|
|
|
|
|
-> Density -- ^ current density of base graph
|
|
|
|
|
-> Density -- ^ new density of expanded graph
|
2013-11-29 19:09:05 +01:00
|
|
|
|
updateDensity adj nodes newNode dens =
|
|
|
|
|
let
|
|
|
|
|
neighbours = A.foldAllS (+) (0::Int)
|
|
|
|
|
$A.traverse nodes id (\f sh -> fromIntegral $adj!(ix2 (f sh) newNode))
|
|
|
|
|
(Z:.n') = A.extent nodes
|
|
|
|
|
n = fromIntegral n'
|
|
|
|
|
in (dens * (n*(n+1)) / 2 + fromIntegral neighbours) * 2 / ((n+1)*(n+2))
|
2013-11-27 13:17:21 +01:00
|
|
|
|
|
2013-12-03 01:06:56 +01:00
|
|
|
|
|
|
|
|
|
-- | Checks a 'Graph' expansion with a single node regarding both the attribute constraints
|
|
|
|
|
-- and a minimum density. If it passes the test the extended graph is returned.
|
|
|
|
|
addPoint :: Adj -- ^ global adjacency matrix of all nodes
|
|
|
|
|
-> Attr -- ^ global attribute matrix
|
|
|
|
|
-> Density -- ^ required minimum graph’s density
|
|
|
|
|
-> MaxDivergence -- ^ allowed divergence per attribute
|
|
|
|
|
-> Int -- ^ equired number of consistent attributes
|
|
|
|
|
-> Graph -- ^ base graph
|
|
|
|
|
-> Int -- ^ node to extend base graph by
|
|
|
|
|
-> Maybe Graph
|
2013-11-29 19:09:05 +01:00
|
|
|
|
addPoint adj attr d div req g@(nodes, _, dens) n =
|
|
|
|
|
let
|
|
|
|
|
constr = constraint attr div req g n
|
|
|
|
|
densNew = updateDensity adj nodes n dens
|
|
|
|
|
in
|
|
|
|
|
case constr of
|
|
|
|
|
Nothing -> Nothing
|
|
|
|
|
(Just c) ->
|
|
|
|
|
case dens >= d of
|
2013-12-02 22:56:30 +01:00
|
|
|
|
True -> Just (A.computeS $nodes ++ A.fromListUnboxed (ix1 1) [n], c, densNew)
|
2013-11-29 19:09:05 +01:00
|
|
|
|
False -> Nothing
|
2013-11-27 13:17:21 +01:00
|
|
|
|
|
2013-12-01 15:29:48 +01:00
|
|
|
|
-- | yields all valid addititons (=neighbours) to a Graph
|
2013-12-03 01:39:24 +01:00
|
|
|
|
addablePoints :: Adj -> Graph -> Vector A.U Bool
|
|
|
|
|
addablePoints adj (ind,_,_) = A.computeS $
|
|
|
|
|
(A.traverse
|
|
|
|
|
adj
|
|
|
|
|
reduceDim
|
|
|
|
|
(foldOr ind))
|
2013-12-03 00:22:51 +01:00
|
|
|
|
where
|
|
|
|
|
|
|
|
|
|
reduceDim :: (A.Shape sh, Integral a) => (sh :. a) -> sh
|
|
|
|
|
reduceDim (a :. b) = a --A.shapeOfList $ tail $ A.listOfShape a
|
|
|
|
|
|
2013-12-03 01:39:24 +01:00
|
|
|
|
foldOr :: (A.Shape sh') => Vector A.U Int -> ((sh' :. Int :. Int) -> Int8) -> (sh' :. Int) -> Bool
|
|
|
|
|
foldOr indlist lookup ind@(a :. pos) = case V.any (== pos) $ A.toUnboxed indlist of
|
|
|
|
|
True -> False
|
|
|
|
|
_ -> (foldl1 (+) [lookup (ind :. i) | i <- (map fromIntegral (A.toList indlist))]) > 0
|
|
|
|
|
|
|
|
|
|
|