packages feed

cnc-spec-compiler-0.2.0.0: Intel/Cnc/Spec/CncGraph.hs

{-# LANGUAGE RecordWildCards, ScopedTypeVariables #-}
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
----------------------------------------------------------------------------------------------------
-- Data types and utilities for working with CnC Specifications (Graphs)
-- Original Author: Ryan Newton
----------------------------------------------------------------------------------------------------
module Intel.Cnc.Spec.CncGraph ( 
				CncSpec (..), CncGraph, 
				CncGraphNode (..), ColName, graphNodeName, isStepC, isReductionC, isTagC, isItemC,
				
                                upstreamNbrs, downstreamNbrs, builtinSteps,
				getStepPrescriber
				
			       ) where

import Intel.Cnc.Spec.Util 
import Intel.Cnc.Spec.AST
import Intel.Cnc.Spec.TagFun
import Data.List as L
import Data.Maybe
import Data.Map
import StringTable.Atom 
import StringTable.AtomMap as AM
import StringTable.AtomSet as AS
import Text.PrettyPrint.HughesPJClass hiding (Style)
import Data.Graph.Inductive as G

-- | The total "Spec" includes the graph and other metadata.
data CncSpec = CncSpec {
  -- | steps, tags, items include all top-level collections in the graph.
  steps :: AtomSet,
  tags  :: AtomMap (Maybe Type),
  items :: AtomMap (Maybe (Type,Type)),
  reductions :: AtomMap (Atom, Exp (), Maybe (Type,Type)), -- Contains 'op' and type.

  graph :: CncGraph,

  -- | appname is metadata, usually corresponding to the name of the .cnc file.
  appname :: String,
  -- Might as well cache this after it is extracted, used by FGL calls:
  nodemap :: NodeMap CncGraphNode,
  -- Annoyingly, FGL nodemaps are essentially unreadable and useless, hence this:
  realmap :: Map CncGraphNode Node,

  -- We store the graph in a "flat" form and separately keep a tree of partitions:
  harchtree :: ()
}
-- deriving (Eq, Ord)

-- | The CnCGraph is a raw graph object without additional metadata and indexes.
-- 
--   NOTE: If a step peforms multiple gets/puts those are treated as
--   SEPARATE EDGES in the graph currently.  (There is no notion of a
--   TagFun returning a set of tags, but that may change.)
type CncGraph = (Gr CncGraphNode (Maybe TagFun))

type ColName = Atom

builtinSteps = [toAtom special_environment_name]

-- | The name of a collection, together with the type of collection (step/item/etc).
data CncGraphNode  = 
    CGSteps      ColName 
  | CGTags       ColName 
  | CGItems      ColName 
  | CGReductions ColName 
 deriving (Eq, Ord, Show)

graphNodeName (CGSteps n) = fromAtom n
graphNodeName (CGTags  n) = fromAtom n
graphNodeName (CGItems n) = fromAtom n
graphNodeName (CGReductions n) = fromAtom n

instance Pretty CncGraphNode where
  pPrint = text . show 

instance Show CncSpec where
  show = show . pPrint

instance Pretty CncSpec where
  pPrint (CncSpec{..}) = 
      text "CncSpec{\n ------------- All Steps ----------------------"    $$ 
	   hcat (intersperse (text ", ") $ L.map (text . fromAtom) $ AS.toList steps) $$
      text "\n ------------- Tag Types ----------------------" $$ 
	   sep (L.map (\(x,y) -> pp((fromAtom x)::String,y)) $ AM.toList tags) $$
      text "\n ------------- Item Types ---------------------" $$ 
	   sep (L.map (\(x,y) -> pp((fromAtom x)::String,y)) $ AM.toList items) $$

      text "\n ----------- Reduction Ops/Types --------------" $$ 
	   sep (L.map (\(x,y) -> pp((fromAtom x)::String,y)) $ AM.toList reductions) $$

      text "\n ----------------- FGL Graph ------------------" $$ 
      text (show graph) $$
      text "}"


----------------------------------------------------------------------------------------------------

-- TODO: Perform basic checks here.
--verifySpec :: CncSpec -> CncSpec
verifySpec spec = 
   spec
   -- All steps are prescribed.
   -- All tags/items have types (for now, for C++)
   -- 

----------------------------------------------------------------------------------------------------


-- | Go over all the edges from a step collection and collect their
--   contributions to getcounts of neighboring item collections.
stepGetCountContributions :: CncSpec -> ColName -> Map ColName Int
--   For now getcounts are simple (static) numbers.  Dynamically
--   valued getcounts may be a useful feature in the future.
stepGetCountContributions spec stepC =
  let 
      nbrs = L.filter isItemC $ 
             upstreamNbrs spec (CGSteps stepC)
  in 
  undefined


-- Get the name of the tag collection that prescribes a given step.
getStepPrescriber :: CncSpec -> ColName -> ColName
getStepPrescriber (CncSpec{..}) atom = 
  case L.filter isTagC labs of 
    [CGTags t] -> t
    ls -> error$ "getStepPrescriber step "++ (fromAtom atom) ++ 
	         " should have exactly one prescribing tag collection, not "++ show (length ls)
 where 
    (nd,_) = mkNode_ nodemap (CGSteps atom)
    preds = pre graph nd
    labs  = catMaybes$ L.map (lab graph) preds

isTagC (CGTags _) = True
isTagC _          = False
isItemC (CGItems _) = True
isItemC _           = False
isStepC (CGSteps _) = True
isStepC _           = False
isReductionC (CGReductions _) = True
isReductionC _                = False


----------------------------------------------------------------------------------------------------

-- | Get upstream neighbors in the CnC graph.
-- This routine sees *through* tag collections.
-- Returns a list of STEP and ITEM collections.
upstreamNbrs :: CncSpec -> CncGraphNode -> [CncGraphNode]
upstreamNbrs = nbrHelper pre

-- | Get downstream neighbors in the CnC graph.
-- This routine sees *through* tag collections.
-- Returns a list of STEP and ITEM collections.
downstreamNbrs :: CncSpec -> CncGraphNode -> [CncGraphNode]
downstreamNbrs = nbrHelper suc

nbrHelper adjacent (spec@CncSpec{..}) nodelab = 
    if gelem nd graph 
    then L.concat$ L.map process labs
    else error$ "upstream/downstream: cannot find neighbors because node is not in graph: "++ show nodelab
 where 
    (nd,_) = mkNode_ nodemap nodelab
    labs  = catMaybes$ L.map (lab graph) (adjacent graph nd)
    process x@(CGSteps _) = [x]
    process x@(CGItems _) = [x]
    process x@(CGReductions _) = [x]
    process x@(CGTags _) = nbrHelper adjacent spec x


-- | Extract a subgraph of the full CnC graph that only contains step collections (including 'env').
stepOnlyGraph :: CncGraph -> Gr ColName ()
stepOnlyGraph = error "stepOnlyGraph: TODO: implement me"


----------------------------------------------------------------------------------------------------