packages feed

hgraph-1.10.0.0: src/HGraph/Directed/Generator/Hereditary/Internal.hs

{-# Language CPP #-}

module HGraph.Directed.Generator.Hereditary.Internal where

import HGraph.Directed as D
import HGraph.Parallel
import HGraph.Debugging

import Data.List
import Data.Maybe
import qualified Data.Map as M
import qualified Data.Set as S
import System.IO (hPutStrLn, stderr)
import Control.Concurrent
import Control.Concurrent.MVar
import Control.Exception
import Control.Monad

data Fingerprint = Fingerprint
  { degreeSequence :: [(Int, Int)]
  } deriving (Eq, Ord)

enumerateParallel fGrow dStart vs = do
  newDigraph     <- newEmptyMVar
  digraphCount   <- newMVar $ length dStart
  candidateCount <- newMVar 0
  mCandidate     <- newEmptyMVar
  mDistinctDigraphs <- newMVar $ foldr 
    (\(dFingerprint, d) m -> M.insertWith (\(n0, ds0) (n1, ds1) -> (n0 + n1, ds0 ++ ds1))
                                          dFingerprint (1, [d]) m)
    M.empty $
    map (\d -> (fingerprint d, d))
        dStart
  forkIO $ mapM_ (\d -> hasLocked (__FILE__ ++ " on line " ++ show __LINE__) $ putMVar newDigraph $ Just (d, vs)) dStart
  let insertDigraph d = do
                        distinct <- readMVar mDistinctDigraphs
                        let dFingerprint = fingerprint d
                            mCandidates = M.lookup dFingerprint distinct
                        case mCandidates of
                             Just (n, candidates) ->
                               if and $ map (not . (D.isIsomorphicToI d)) candidates then do
                                  modifyMVar_ mDistinctDigraphs $ insertNewDigraph d dFingerprint n candidates 
                                  return True
                               else
                                  return False
                             Nothing -> do
                               modifyMVar_ mDistinctDigraphs $ insertNewDigraph d dFingerprint 0 [] 
                               return True

  generateDigraph <- processJobList
    (\(d, gen0, vs') -> do
      isNew <- if gen0 then
                  return True
               else
                  insertDigraph d
      if isNew then
         case vs' of
           [] -> return ( []
                        , if gen0 then [] else [(d, True)])
           (v : vs'') -> do
             let ds = fGrow d v
             return (map (\d' -> (d', False, vs'')) ds
                    , if gen0 then [] else [(d, False)])
      else
         return ([], [])
    )
    (map (\d -> (d, True, vs)) dStart)
  return generateDigraph

enumerateParallel' fGrow dStart vs = do
  generate <- enumerateParallel fGrow dStart vs
  return (fmap (fmap fst) generate)

exhaust generator =
  let loop = do
             g <- generator
             case g of
               Just g' -> do
                 gs <- loop
                 return $ g' : gs
               Nothing ->
                 return []
  in loop

random fChoices fCheck dStart vs = return $ head dStart

insertNewDigraph d
                 dFingerprint
                 checkedCandidates
                 candidates
                 knownDigraphs =
  do
  case M.lookup dFingerprint knownDigraphs of
       Just (n', candidates') -> do
        if and $ map (not . (isIsomorphicToI d)) $ take (n' - checkedCandidates) candidates' then
           addToDatabase n' candidates'
        else
           return knownDigraphs
       Nothing -> addToDatabase checkedCandidates candidates
  where
    addToDatabase n' candidates' = do
      return $ M.insert dFingerprint (n' + 1, d : candidates') knownDigraphs

fingerprint d = 
  Fingerprint
  { degreeSequence = sort $ map (\v -> (D.indegree d v, D.outdegree d v)) $ D.vertices d
  }