moonlight-category-0.1.0.0: bench/abstract/Adhesive/Graph.hs
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
module Adhesive.Graph
( finiteGraphDPOBenchmarks,
)
where
import BenchSupport (boolWeight)
import Control.DeepSeq (NFData (..))
import Control.Monad (guard)
import Data.Function ((&))
import Data.IntMap.Strict (IntMap)
import Data.IntMap.Strict qualified as IntMap
import Data.Vector (Vector)
import Data.Vector qualified as Vector
import Moonlight.Category.Pure.Adhesive
( AdhesiveCategory (..),
DenseIntSet,
MonicMatchComponents (..),
PBPOAdhesiveCategory (..),
PBPOComplementComponents (..),
PBPOComplementWitness,
PushoutComplementWitness,
PushoutComplementComponents (..),
denseIntSetDifference,
denseIntSetFoldl',
denseIntSetFromAscList,
denseIntSetFull,
denseIntSetIntersection,
denseIntSetIntersects,
denseIntSetInterval,
denseIntSetIsSubsetOf,
denseIntSetMember,
denseIntSetSize,
denseIntSetUnion,
denseIntSetUniverseSize,
denseIntSetWeight,
monicMatchArrow,
pbpoComplement,
pbpoComplementBorrowedLeg,
pbpoComplementPullbackObject,
pbpoComplementPullbackToBorrowed,
pbpoComplementPullbackToMatch,
pbpoComplementPushoutFromComplement,
pbpoComplementPushoutFromMatch,
pbpoComplementPushoutObject,
pbpoComplementResidualLeg,
pbpoPullbackSquareCommutes,
pbpoPushoutSquareCommutes,
pushoutComplement,
pushoutComplementBorrowedLeg,
pushoutComplementObject,
pushoutComplementResidualLeg,
pushoutComplementSquareCommutes,
witnessMonic,
)
import Moonlight.Category.Pure.Category (Category (..))
import Moonlight.Category.Pure.Limits (HasPullbacks (..), HasPushouts (..), pullback, pushout)
import Test.Tasty.Bench (Benchmark, bench, bgroup, env, nf)
newtype GraphId = GraphId {unGraphId :: Int}
deriving stock (Eq, Ord, Show)
data GraphCategory = GraphCategory
{ graphCategoryCarrier :: !GraphCarrier
}
deriving stock (Show)
data GraphTwoMor
data GraphCompositor = GraphCompositor
data GraphCategoryError
= GraphBoundaryMismatch
| GraphCompositeInvalid
deriving stock (Eq, Show)
data GraphEdge = GraphEdge
{ graphEdgeSource :: !Int,
graphEdgeTarget :: !Int
}
deriving stock (Eq, Show)
data GraphCarrier = GraphCarrier
{ graphCarrierId :: !GraphId,
graphCarrierVertices :: !DenseIntSet,
graphCarrierEdgeIds :: !DenseIntSet,
graphCarrierEdges :: !(IntMap GraphEdge),
graphCarrierIncidentEdges :: !(Vector DenseIntSet)
}
deriving stock (Show)
data GraphObject = GraphObject
{ graphObjectCarrierId :: !GraphId,
graphObjectVertices :: !DenseIntSet,
graphObjectEdges :: !DenseIntSet,
graphObjectVertexCount :: !Int,
graphObjectEdgeCount :: !Int
}
deriving stock (Show)
data GraphDeletionDelta = GraphDeletionDelta
{ graphDeletionVertices :: !DenseIntSet,
graphDeletionEdges :: !DenseIntSet
}
deriving stock (Eq, Show)
data GraphMorphism = GraphMorphism
{ graphMorphismSource :: !GraphObject,
graphMorphismTarget :: !GraphObject,
graphMorphismKnownComplement :: !(Maybe GraphDeletionDelta)
}
deriving stock (Show)
data GraphRewriteCase = GraphRewriteCase
{ graphRewriteCategory :: !GraphCategory,
graphRewriteRuleLeg :: !GraphMorphism,
graphRewriteMatch :: !GraphMorphism
}
deriving stock (Show)
data PreparedGraphRewriteCase = PreparedGraphRewriteCase
{ preparedGraphRewrite :: !GraphRewriteCase,
preparedGraphComplement :: !(PushoutComplementWitness GraphCategory),
preparedGraphPBPO :: !(PBPOComplementWitness GraphCategory)
}
data PreparedGraphRewriteBatch = PreparedGraphRewriteBatch
{ preparedGraphAmbientSize :: !Int,
preparedGraphCases :: ![PreparedGraphRewriteCase]
}
instance Eq GraphObject where
left == right =
graphObjectCarrierId left == graphObjectCarrierId right
&& graphObjectVertexCount left == graphObjectVertexCount right
&& graphObjectEdgeCount left == graphObjectEdgeCount right
&& graphObjectVertices left == graphObjectVertices right
&& graphObjectEdges left == graphObjectEdges right
instance Eq GraphMorphism where
left == right =
graphMorphismSource left == graphMorphismSource right
&& graphMorphismTarget left == graphMorphismTarget right
instance NFData GraphId where
rnf graphId =
unGraphId graphId `seq` ()
instance NFData GraphEdge where
rnf edge =
graphEdgeSource edge
`seq` graphEdgeTarget edge
`seq` ()
instance NFData GraphCarrier where
rnf carrier =
rnf (graphCarrierId carrier)
`seq` denseIntSetSize (graphCarrierVertices carrier)
`seq` denseIntSetSize (graphCarrierEdgeIds carrier)
`seq` rnf (graphCarrierEdges carrier)
`seq` Vector.foldl' (\forced incidentEdges -> denseIntSetSize incidentEdges `seq` forced) () (graphCarrierIncidentEdges carrier)
instance NFData GraphCategory where
rnf categoryValue =
rnf (graphCategoryCarrier categoryValue)
instance NFData GraphObject where
rnf graph =
rnf (graphObjectCarrierId graph)
`seq` denseIntSetSize (graphObjectVertices graph)
`seq` denseIntSetSize (graphObjectEdges graph)
`seq` graphObjectVertexCount graph
`seq` graphObjectEdgeCount graph
`seq` ()
instance NFData GraphDeletionDelta where
rnf delta =
denseIntSetSize (graphDeletionVertices delta)
`seq` denseIntSetSize (graphDeletionEdges delta)
`seq` ()
instance NFData GraphMorphism where
rnf morphism =
rnf (graphMorphismSource morphism)
`seq` rnf (graphMorphismTarget morphism)
`seq` rnf (graphMorphismKnownComplement morphism)
instance NFData GraphRewriteCase where
rnf rewriteCase =
rnf (graphRewriteCategory rewriteCase)
`seq` rnf (graphRewriteRuleLeg rewriteCase)
`seq` rnf (graphRewriteMatch rewriteCase)
instance NFData (PushoutComplementWitness GraphCategory) where
rnf witness =
graphPushoutComplementWitnessWeight witness `seq` ()
instance NFData (PBPOComplementWitness GraphCategory) where
rnf witness =
graphPBPOComplementWitnessWeight witness `seq` ()
instance NFData PreparedGraphRewriteCase where
rnf prepared =
rnf (preparedGraphRewrite prepared)
`seq` rnf (preparedGraphComplement prepared)
`seq` rnf (preparedGraphPBPO prepared)
instance NFData PreparedGraphRewriteBatch where
rnf prepared =
preparedGraphAmbientSize prepared
`seq` rnf (preparedGraphCases prepared)
instance Category GraphCategory where
type Ob GraphCategory = GraphObject
type Mor GraphCategory = GraphMorphism
type TwoMor GraphCategory = GraphTwoMor
type Compositor GraphCategory = GraphCompositor
type CategoryError GraphCategory = GraphCategoryError
identity categoryValue graph
| graphObjectCarrierId graph == graphCarrierId (graphCategoryCarrier categoryValue) =
Right (graphTrustedInclusion graph graph)
| otherwise =
Left GraphBoundaryMismatch
compose categoryValue leftMorphism rightMorphism
| not (graphMorphismValidIn categoryValue leftMorphism)
|| not (graphMorphismValidIn categoryValue rightMorphism) =
Left GraphBoundaryMismatch
| graphMorphismTarget rightMorphism /= graphMorphismSource leftMorphism =
Left GraphBoundaryMismatch
| otherwise =
Right (graphTrustedInclusion (graphMorphismSource rightMorphism) (graphMorphismTarget leftMorphism), GraphCompositor)
source categoryValue morphism
| graphMorphismValidIn categoryValue morphism =
Right (graphMorphismSource morphism)
| otherwise =
Left GraphBoundaryMismatch
target categoryValue morphism
| graphMorphismValidIn categoryValue morphism =
Right (graphMorphismTarget morphism)
| otherwise =
Left GraphBoundaryMismatch
instance HasPullbacks GraphCategory where
pullback categoryValue leftMorphism rightMorphism
| graphMorphismValidIn categoryValue leftMorphism
&& graphMorphismValidIn categoryValue rightMorphism
&& graphMorphismTarget leftMorphism == graphMorphismTarget rightMorphism = do
pullbackObjectValue <-
graphIntersectionObject
(graphMorphismSource leftMorphism)
(graphMorphismSource rightMorphism)
pure
( pullbackObjectValue,
graphTrustedInclusion pullbackObjectValue (graphMorphismSource leftMorphism),
graphTrustedInclusion pullbackObjectValue (graphMorphismSource rightMorphism)
)
| otherwise =
Nothing
pullbackMediator categoryValue leftMorphism rightMorphism coneLeft coneRight
| graphMorphismValidIn categoryValue leftMorphism
&& graphMorphismValidIn categoryValue rightMorphism
&& graphMorphismValidIn categoryValue coneLeft
&& graphMorphismValidIn categoryValue coneRight
&& graphMorphismTarget leftMorphism == graphMorphismTarget rightMorphism
&& graphMorphismTarget coneLeft == graphMorphismSource leftMorphism
&& graphMorphismTarget coneRight == graphMorphismSource rightMorphism
&& graphMorphismSource coneLeft == graphMorphismSource coneRight = do
pullbackObjectValue <-
graphIntersectionObject
(graphMorphismSource leftMorphism)
(graphMorphismSource rightMorphism)
pure (graphTrustedInclusion (graphMorphismSource coneLeft) pullbackObjectValue)
| otherwise =
Nothing
instance HasPushouts GraphCategory where
pushout categoryValue leftMorphism rightMorphism
| graphMorphismValidIn categoryValue leftMorphism
&& graphMorphismValidIn categoryValue rightMorphism
&& graphMorphismSource leftMorphism == graphMorphismSource rightMorphism = do
pushoutObjectValue <-
graphCompatibleUnion
(graphMorphismTarget leftMorphism)
(graphMorphismTarget rightMorphism)
pure
( pushoutObjectValue,
graphTrustedInclusion (graphMorphismTarget leftMorphism) pushoutObjectValue,
graphTrustedInclusion (graphMorphismTarget rightMorphism) pushoutObjectValue
)
| otherwise =
Nothing
instance AdhesiveCategory GraphCategory where
monicMatchComponents categoryValue morphism
| graphMorphismValidIn categoryValue morphism =
Just (MonicMatchComponents morphism)
| otherwise =
Nothing
pushoutComplementComponents categoryValue ruleLeg monicMatch = do
let carrier = graphCategoryCarrier categoryValue
matchArrow = monicMatchArrow monicMatch
kernelObject = graphMorphismSource ruleLeg
hostObject = graphMorphismTarget matchArrow
guard (graphMorphismValidIn categoryValue ruleLeg)
guard (graphMorphismValidIn categoryValue matchArrow)
guard (graphMorphismTarget ruleLeg == graphMorphismSource matchArrow)
guard (graphObjectCarrierId hostObject == graphCarrierId carrier)
deletionDelta <- graphMorphismDeletionDelta ruleLeg
let deletedGraphVertices = graphDeletionVertices deletionDelta
deletedGraphEdges = graphDeletionEdges deletionDelta
danglingEdges <- graphHasDanglingEdges carrier hostObject deletedGraphVertices deletedGraphEdges
guard (not danglingEdges)
complementObjectValue <-
graphObjectRemoveAfterDanglingCheck deletedGraphVertices deletedGraphEdges hostObject
pure
PushoutComplementComponents
{ pushoutComplementComponentObject = complementObjectValue,
pushoutComplementComponentBorrowedLeg = graphTrustedInclusion complementObjectValue hostObject,
pushoutComplementComponentResidualLeg = graphTrustedInclusion kernelObject complementObjectValue
}
instance PBPOAdhesiveCategory GraphCategory where
pbpoComplementComponents categoryValue ruleLeg monicMatch = do
pushoutComplementComponentsValue <- pushoutComplementComponents categoryValue ruleLeg monicMatch
let matchArrow = monicMatchArrow monicMatch
pullbackObjectValue = graphMorphismSource ruleLeg
pullbackToBorrowed = pushoutComplementComponentResidualLeg pushoutComplementComponentsValue
pullbackToMatch = ruleLeg
pushoutObjectValue = graphMorphismTarget matchArrow
pushoutFromComplement = pushoutComplementComponentBorrowedLeg pushoutComplementComponentsValue
pushoutFromMatch = matchArrow
pure
PBPOComplementComponents
{ pbpoComplementComponentPullbackObject = pullbackObjectValue,
pbpoComplementComponentPullbackToBorrowed = pullbackToBorrowed,
pbpoComplementComponentPullbackToMatch = pullbackToMatch,
pbpoComplementComponentPushoutObject = pushoutObjectValue,
pbpoComplementComponentPushoutFromComplement = pushoutFromComplement,
pbpoComplementComponentPushoutFromMatch = pushoutFromMatch,
pbpoComplementComponentBorrowedLeg = pushoutComplementComponentBorrowedLeg pushoutComplementComponentsValue,
pbpoComplementComponentResidualLeg = pushoutComplementComponentResidualLeg pushoutComplementComponentsValue
}
finiteGraphDPOBenchmarks :: Benchmark
finiteGraphDPOBenchmarks =
bgroup
"pre-matched indexed-subgraph DPO/PBPO workload"
(fmap finiteGraphDPOBenchmark [32, 128, 512])
finiteGraphDPOBenchmark :: Int -> Benchmark
finiteGraphDPOBenchmark ambientSize =
env (prepareGraphRewriteBatch ambientSize) $ \prepared ->
bgroup
("ambient vertices=" <> show ambientSize <> ", cases=64")
[ bench "pullback graph intersections" (nf graphPullbackBatchWeight prepared),
bench "pushout graph unions" (nf graphPushoutBatchWeight prepared),
bench "monic match validation" (nf graphMonicBatchWeight prepared),
bench "DPO indexed witness construction shape" (nf graphPushoutComplementShapeBatchWeight prepared),
bench "DPO indexed witness full projection" (nf graphPushoutComplementBatchWeight prepared),
bench "DPO square commute checks" (nf graphPushoutComplementCommuteBatchWeight prepared),
bench "PBPO specialized witness construction shape" (nf graphPBPOComplementShapeBatchWeight prepared),
bench "PBPO specialized witness full projection" (nf graphPBPOComplementBatchWeight prepared),
bench "PBPO pullback+pushout commute checks" (nf graphPBPOCommuteBatchWeight prepared)
]
prepareGraphRewriteBatch :: Int -> IO PreparedGraphRewriteBatch
prepareGraphRewriteBatch ambientSize =
case traverse (preparedGraphRewriteCase ambientSize) [0 .. 63] of
Nothing ->
ioError (userError ("failed to prepare finite graph DPO benchmark for ambient size " <> show ambientSize))
Just rewriteCases ->
let prepared =
PreparedGraphRewriteBatch
{ preparedGraphAmbientSize = ambientSize,
preparedGraphCases = rewriteCases
}
in rnf prepared `seq` pure prepared
preparedGraphRewriteCase :: Int -> Int -> Maybe PreparedGraphRewriteCase
preparedGraphRewriteCase ambientSize seed = do
rewriteCase <- graphRewriteCase ambientSize seed
complement <- graphComplementWitness rewriteCase
pbpo <- graphPBPOWitness rewriteCase
pure
PreparedGraphRewriteCase
{ preparedGraphRewrite = rewriteCase,
preparedGraphComplement = complement,
preparedGraphPBPO = pbpo
}
graphRewriteCase :: Int -> Int -> Maybe GraphRewriteCase
graphRewriteCase ambientSize seed = do
kernelVertices <- graphRangeSet normalizedSize 0 kernelCount
deletedVertices <- graphRangeSet normalizedSize kernelCount deletedCount
ambientVertices <- denseIntSetFull normalizedSize
let kernelEdgePairs =
graphPathEdgePairs (graphRangeList 0 kernelCount)
deletedEdgePairs =
graphPathEdgePairs (graphRangeList kernelCount deletedCount)
contextEdgePairs =
graphPathEdgePairs (graphRangeList (kernelCount + deletedCount) contextCount)
kernelEdgeCount =
length kernelEdgePairs
deletedEdgeCount =
length deletedEdgePairs
contextEdgeCount =
length contextEdgePairs
edgeUniverse =
kernelEdgeCount + deletedEdgeCount + contextEdgeCount
ambientEdges =
graphEdgesFromPairs (kernelEdgePairs <> deletedEdgePairs <> contextEdgePairs)
kernelEdges <- graphRangeSet edgeUniverse 0 kernelEdgeCount
deletedEdges <- graphRangeSet edgeUniverse kernelEdgeCount deletedEdgeCount
ruleVertices <- denseIntSetUnion kernelVertices deletedVertices
ruleEdges <- denseIntSetUnion kernelEdges deletedEdges
ambientEdgeIds <- denseIntSetFull edgeUniverse
ambientCarrier <- graphCarrierFromEdges graphId ambientVertices ambientEdges
kernelGraph <- graphObjectFromParts ambientCarrier kernelVertices kernelEdges
ruleGraph <- graphObjectFromParts ambientCarrier ruleVertices ruleEdges
ambientGraph <- graphObjectFromParts ambientCarrier ambientVertices ambientEdgeIds
ruleLeg <- graphSubobjectInclusion kernelGraph ruleGraph
matchArrow <- graphSubobjectInclusion ruleGraph ambientGraph
pure
GraphRewriteCase
{ graphRewriteCategory = GraphCategory ambientCarrier,
graphRewriteRuleLeg = ruleLeg,
graphRewriteMatch = matchArrow
}
where
normalizedSize =
max 8 ambientSize
kernelCount =
max 2 (normalizedSize `div` 4)
deletedCount =
max 2 (normalizedSize `div` 4)
contextCount =
max 2 (normalizedSize - kernelCount - deletedCount)
graphId =
GraphId (ambientSize * 1024 + seed)
graphCarrierFromEdges :: GraphId -> DenseIntSet -> IntMap GraphEdge -> Maybe GraphCarrier
graphCarrierFromEdges graphId vertices edges = do
let edgeUniverseSize = IntMap.size edges
edgeIds <- denseIntSetFull edgeUniverseSize
guard (IntMap.keys edges == [0 .. edgeUniverseSize - 1])
guard (graphEdgesClosedOver vertices edges)
incidentEdges <- graphIncidentIndex (denseIntSetUniverseSize vertices) edgeUniverseSize edges
pure
GraphCarrier
{ graphCarrierId = graphId,
graphCarrierVertices = vertices,
graphCarrierEdgeIds = edgeIds,
graphCarrierEdges = edges,
graphCarrierIncidentEdges = incidentEdges
}
graphObjectFromParts :: GraphCarrier -> DenseIntSet -> DenseIntSet -> Maybe GraphObject
graphObjectFromParts carrier vertices edgeIds = do
let objectValue =
GraphObject
{ graphObjectCarrierId = graphCarrierId carrier,
graphObjectVertices = vertices,
graphObjectEdges = edgeIds,
graphObjectVertexCount = denseIntSetSize vertices,
graphObjectEdgeCount = denseIntSetSize edgeIds
}
guard (denseIntSetIsSubsetOf vertices (graphCarrierVertices carrier) == Just True)
guard (denseIntSetIsSubsetOf edgeIds (graphCarrierEdgeIds carrier) == Just True)
guard (graphObjectClosed carrier objectValue)
pure objectValue
graphRangeSet :: Int -> Int -> Int -> Maybe DenseIntSet
graphRangeSet =
denseIntSetInterval
graphRangeList :: Int -> Int -> [Int]
graphRangeList start count =
[start .. start + count - 1]
graphPathEdgePairs :: [Int] -> [(Int, Int)]
graphPathEdgePairs vertices =
zip vertices (drop 1 vertices)
graphEdgesFromPairs :: [(Int, Int)] -> IntMap GraphEdge
graphEdgesFromPairs pairs =
zip [0 ..] pairs
& fmap (\(edgeId, (sourceVertex, targetVertex)) -> (edgeId, GraphEdge sourceVertex targetVertex))
& IntMap.fromAscList
graphIncidentIndex :: Int -> Int -> IntMap GraphEdge -> Maybe (Vector DenseIntSet)
graphIncidentIndex vertexUniverseSize edgeUniverseSize edges =
traverse
(denseIntSetFromAscList edgeUniverseSize . graphIncidentEdgeIds edges)
(Vector.generate vertexUniverseSize id)
graphIncidentEdgeIds :: IntMap GraphEdge -> Int -> [Int]
graphIncidentEdgeIds edges vertex =
[ edgeId
| (edgeId, edge) <- IntMap.toAscList edges,
graphEdgeSource edge == vertex || graphEdgeTarget edge == vertex
]
graphObjectVertexSet :: GraphObject -> DenseIntSet
graphObjectVertexSet =
graphObjectVertices
graphObjectEdgeSet :: GraphObject -> DenseIntSet
graphObjectEdgeSet =
graphObjectEdges
graphEdgesClosedOver :: DenseIntSet -> IntMap GraphEdge -> Bool
graphEdgesClosedOver vertices edges =
edges
& IntMap.elems
& all
( \edge ->
denseIntSetMember (graphEdgeSource edge) vertices
&& denseIntSetMember (graphEdgeTarget edge) vertices
)
graphObjectClosed :: GraphCarrier -> GraphObject -> Bool
graphObjectClosed carrier graph =
denseIntSetFoldl'
(\closed edgeId -> closed && graphObjectContainsEdgeEndpoints carrier graph edgeId)
True
(graphObjectEdgeSet graph)
graphObjectContainsEdgeEndpoints :: GraphCarrier -> GraphObject -> Int -> Bool
graphObjectContainsEdgeEndpoints carrier graph edgeId =
case IntMap.lookup edgeId (graphCarrierEdges carrier) of
Just edge ->
denseIntSetMember (graphEdgeSource edge) (graphObjectVertices graph)
&& denseIntSetMember (graphEdgeTarget edge) (graphObjectVertices graph)
Nothing ->
False
graphObjectInCategory :: GraphCategory -> GraphObject -> Bool
graphObjectInCategory categoryValue graph =
graphObjectCarrierId graph == graphCarrierId (graphCategoryCarrier categoryValue)
graphMorphismValidIn :: GraphCategory -> GraphMorphism -> Bool
graphMorphismValidIn categoryValue morphism =
graphObjectInCategory categoryValue (graphMorphismSource morphism)
&& graphObjectInCategory categoryValue (graphMorphismTarget morphism)
&& graphMorphismIsInclusion morphism
graphMorphismIsInclusion :: GraphMorphism -> Bool
graphMorphismIsInclusion morphism =
graphObjectCarrierId (graphMorphismSource morphism) == graphObjectCarrierId (graphMorphismTarget morphism)
graphObjectIsSubobjectOf :: GraphObject -> GraphObject -> Bool
graphObjectIsSubobjectOf sourceGraph targetGraph =
graphObjectCarrierId sourceGraph == graphObjectCarrierId targetGraph
&& denseIntSetIsSubsetOf (graphObjectVertices sourceGraph) (graphObjectVertices targetGraph) == Just True
&& denseIntSetIsSubsetOf (graphObjectEdges sourceGraph) (graphObjectEdges targetGraph) == Just True
graphSubobjectInclusion :: GraphObject -> GraphObject -> Maybe GraphMorphism
graphSubobjectInclusion sourceGraph targetGraph = do
guard (graphObjectIsSubobjectOf sourceGraph targetGraph)
deletionDelta <- graphDeletionDelta sourceGraph targetGraph
pure (graphTrustedInclusionWithDelta sourceGraph targetGraph (Just deletionDelta))
graphTrustedInclusion :: GraphObject -> GraphObject -> GraphMorphism
graphTrustedInclusion sourceGraph targetGraph =
graphTrustedInclusionWithDelta sourceGraph targetGraph Nothing
graphTrustedInclusionWithDelta :: GraphObject -> GraphObject -> Maybe GraphDeletionDelta -> GraphMorphism
graphTrustedInclusionWithDelta sourceGraph targetGraph complementDelta =
GraphMorphism
{ graphMorphismSource = sourceGraph,
graphMorphismTarget = targetGraph,
graphMorphismKnownComplement = complementDelta
}
graphMorphismDeletionDelta :: GraphMorphism -> Maybe GraphDeletionDelta
graphMorphismDeletionDelta morphism =
case graphMorphismKnownComplement morphism of
Just deletionDelta ->
Just deletionDelta
Nothing ->
graphDeletionDelta (graphMorphismSource morphism) (graphMorphismTarget morphism)
graphDeletionDelta :: GraphObject -> GraphObject -> Maybe GraphDeletionDelta
graphDeletionDelta sourceGraph targetGraph = do
deletedVertices <- denseIntSetDifference (graphObjectVertexSet targetGraph) (graphObjectVertexSet sourceGraph)
deletedEdges <- denseIntSetDifference (graphObjectEdgeSet targetGraph) (graphObjectEdgeSet sourceGraph)
pure
GraphDeletionDelta
{ graphDeletionVertices = deletedVertices,
graphDeletionEdges = deletedEdges
}
graphIntersectionObject :: GraphObject -> GraphObject -> Maybe GraphObject
graphIntersectionObject leftGraph rightGraph = do
guard (graphObjectCarrierId leftGraph == graphObjectCarrierId rightGraph)
intersectionVertices <- denseIntSetIntersection (graphObjectVertexSet leftGraph) (graphObjectVertexSet rightGraph)
intersectionEdges <- denseIntSetIntersection (graphObjectEdgeSet leftGraph) (graphObjectEdgeSet rightGraph)
pure
GraphObject
{ graphObjectCarrierId = graphObjectCarrierId leftGraph,
graphObjectVertices = intersectionVertices,
graphObjectEdges = intersectionEdges,
graphObjectVertexCount = denseIntSetSize intersectionVertices,
graphObjectEdgeCount = denseIntSetSize intersectionEdges
}
graphCompatibleUnion :: GraphObject -> GraphObject -> Maybe GraphObject
graphCompatibleUnion leftGraph rightGraph = do
guard (graphObjectCarrierId leftGraph == graphObjectCarrierId rightGraph)
unionVertices <- denseIntSetUnion (graphObjectVertexSet leftGraph) (graphObjectVertexSet rightGraph)
unionEdges <- denseIntSetUnion (graphObjectEdgeSet leftGraph) (graphObjectEdgeSet rightGraph)
pure
GraphObject
{ graphObjectCarrierId = graphObjectCarrierId leftGraph,
graphObjectVertices = unionVertices,
graphObjectEdges = unionEdges,
graphObjectVertexCount = denseIntSetSize unionVertices,
graphObjectEdgeCount = denseIntSetSize unionEdges
}
graphObjectRemoveAfterDanglingCheck :: DenseIntSet -> DenseIntSet -> GraphObject -> Maybe GraphObject
graphObjectRemoveAfterDanglingCheck deletedVertices deletedEdges graph =
do
remainingVertices <- denseIntSetDifference (graphObjectVertices graph) deletedVertices
remainingEdges <- denseIntSetDifference (graphObjectEdges graph) deletedEdges
pure
GraphObject
{ graphObjectCarrierId = graphObjectCarrierId graph,
graphObjectVertices = remainingVertices,
graphObjectEdges = remainingEdges,
graphObjectVertexCount = denseIntSetSize remainingVertices,
graphObjectEdgeCount = denseIntSetSize remainingEdges
}
graphHasDanglingEdges :: GraphCarrier -> GraphObject -> DenseIntSet -> DenseIntSet -> Maybe Bool
graphHasDanglingEdges carrier hostGraph deletedVertices deletedEdges =
do
hostEdgesAfterDeletion <- denseIntSetDifference (graphObjectEdges hostGraph) deletedEdges
denseIntSetFoldl' (detectDanglingEdge hostEdgesAfterDeletion) (Just False) deletedVertices
where
detectDanglingEdge hostEdgesAfterDeletion danglingFound vertex =
case danglingFound of
Nothing ->
Nothing
Just True ->
Just True
Just False ->
vertexHasDanglingEdge hostEdgesAfterDeletion vertex
vertexHasDanglingEdge hostEdgesAfterDeletion vertex =
case graphCarrierIncidentEdges carrier Vector.!? vertex of
Nothing ->
Nothing
Just incidentEdges ->
denseIntSetIntersects hostEdgesAfterDeletion incidentEdges
graphPullbackBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPullbackBatchWeight =
graphBatchWeight graphPullbackWeight
graphPushoutBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPushoutBatchWeight =
graphBatchWeight graphPushoutWeight
graphMonicBatchWeight :: PreparedGraphRewriteBatch -> Int
graphMonicBatchWeight =
graphBatchWeight graphMonicWeight
graphPushoutComplementBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPushoutComplementBatchWeight =
graphBatchWeight graphPushoutComplementWeight
graphPushoutComplementShapeBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPushoutComplementShapeBatchWeight =
graphBatchWeight graphPushoutComplementShapeWeight
graphPushoutComplementCommuteBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPushoutComplementCommuteBatchWeight =
graphBatchWeight graphPushoutComplementCommuteWeight
graphPBPOComplementBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPBPOComplementBatchWeight =
graphBatchWeight graphPBPOComplementWeight
graphPBPOComplementShapeBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPBPOComplementShapeBatchWeight =
graphBatchWeight graphPBPOComplementShapeWeight
graphPBPOCommuteBatchWeight :: PreparedGraphRewriteBatch -> Int
graphPBPOCommuteBatchWeight =
graphBatchWeight graphPBPOCommuteWeight
graphBatchWeight :: (PreparedGraphRewriteCase -> Int) -> PreparedGraphRewriteBatch -> Int
graphBatchWeight weight prepared =
preparedGraphCases prepared
& fmap weight
& sum
graphPullbackWeight :: PreparedGraphRewriteCase -> Int
graphPullbackWeight prepared =
maybe
0
graphPullbackTripleWeight
(pullback (graphPreparedCategory prepared) (pushoutComplementBorrowedLeg (preparedGraphComplement prepared)) (graphRewriteMatch (preparedGraphRewrite prepared)))
graphPushoutWeight :: PreparedGraphRewriteCase -> Int
graphPushoutWeight prepared =
maybe
0
graphPushoutTripleWeight
(pushout (graphPreparedCategory prepared) (pushoutComplementResidualLeg (preparedGraphComplement prepared)) (graphRewriteRuleLeg (preparedGraphRewrite prepared)))
graphMonicWeight :: PreparedGraphRewriteCase -> Int
graphMonicWeight prepared =
let rewriteCase = preparedGraphRewrite prepared
in maybe 0 (graphMorphismWeight . monicMatchArrow) (witnessMonic (graphRewriteCategory rewriteCase) (graphRewriteMatch rewriteCase))
graphPushoutComplementWeight :: PreparedGraphRewriteCase -> Int
graphPushoutComplementWeight prepared =
let rewriteCase = preparedGraphRewrite prepared
in maybe 0 graphPushoutComplementWitnessWeight (graphComplementWitness rewriteCase)
graphPushoutComplementShapeWeight :: PreparedGraphRewriteCase -> Int
graphPushoutComplementShapeWeight prepared =
let rewriteCase = preparedGraphRewrite prepared
in maybe 0 graphPushoutComplementWitnessShapeWeight (graphComplementWitness rewriteCase)
graphPushoutComplementCommuteWeight :: PreparedGraphRewriteCase -> Int
graphPushoutComplementCommuteWeight prepared =
boolWeight (pushoutComplementSquareCommutes (graphPreparedCategory prepared) (preparedGraphComplement prepared))
graphPBPOComplementWeight :: PreparedGraphRewriteCase -> Int
graphPBPOComplementWeight prepared =
let rewriteCase = preparedGraphRewrite prepared
in maybe 0 graphPBPOComplementWitnessWeight (graphPBPOWitness rewriteCase)
graphPBPOComplementShapeWeight :: PreparedGraphRewriteCase -> Int
graphPBPOComplementShapeWeight prepared =
let rewriteCase = preparedGraphRewrite prepared
in maybe 0 graphPBPOComplementWitnessShapeWeight (graphPBPOWitness rewriteCase)
graphPBPOCommuteWeight :: PreparedGraphRewriteCase -> Int
graphPBPOCommuteWeight prepared =
let witness = preparedGraphPBPO prepared
categoryValue = graphPreparedCategory prepared
in boolWeight (pbpoPullbackSquareCommutes categoryValue witness)
+ boolWeight (pbpoPushoutSquareCommutes categoryValue witness)
graphPreparedCategory :: PreparedGraphRewriteCase -> GraphCategory
graphPreparedCategory =
graphRewriteCategory . preparedGraphRewrite
graphComplementWitness :: GraphRewriteCase -> Maybe (PushoutComplementWitness GraphCategory)
graphComplementWitness rewriteCase = do
monicWitness <- witnessMonic (graphRewriteCategory rewriteCase) (graphRewriteMatch rewriteCase)
pushoutComplement (graphRewriteCategory rewriteCase) (graphRewriteRuleLeg rewriteCase) monicWitness
graphPBPOWitness :: GraphRewriteCase -> Maybe (PBPOComplementWitness GraphCategory)
graphPBPOWitness rewriteCase = do
monicWitness <- witnessMonic (graphRewriteCategory rewriteCase) (graphRewriteMatch rewriteCase)
pbpoComplement (graphRewriteCategory rewriteCase) (graphRewriteRuleLeg rewriteCase) monicWitness
graphPullbackTripleWeight :: (GraphObject, GraphMorphism, GraphMorphism) -> Int
graphPullbackTripleWeight (objectValue, leftLeg, rightLeg) =
graphObjectWeight objectValue
+ graphMorphismWeight leftLeg
+ graphMorphismWeight rightLeg
graphPushoutTripleWeight :: (GraphObject, GraphMorphism, GraphMorphism) -> Int
graphPushoutTripleWeight =
graphPullbackTripleWeight
graphPushoutComplementWitnessWeight :: PushoutComplementWitness GraphCategory -> Int
graphPushoutComplementWitnessWeight witness =
graphObjectWeight (pushoutComplementObject witness)
+ graphMorphismWeight (pushoutComplementBorrowedLeg witness)
+ graphMorphismWeight (pushoutComplementResidualLeg witness)
graphPushoutComplementWitnessShapeWeight :: PushoutComplementWitness GraphCategory -> Int
graphPushoutComplementWitnessShapeWeight witness =
graphObjectShapeWeight (pushoutComplementObject witness)
+ graphMorphismShapeWeight (pushoutComplementBorrowedLeg witness)
+ graphMorphismShapeWeight (pushoutComplementResidualLeg witness)
graphPBPOComplementWitnessWeight :: PBPOComplementWitness GraphCategory -> Int
graphPBPOComplementWitnessWeight witness =
graphObjectWeight (pbpoComplementPullbackObject witness)
+ graphMorphismWeight (pbpoComplementPullbackToBorrowed witness)
+ graphMorphismWeight (pbpoComplementPullbackToMatch witness)
+ graphObjectWeight (pbpoComplementPushoutObject witness)
+ graphMorphismWeight (pbpoComplementPushoutFromComplement witness)
+ graphMorphismWeight (pbpoComplementPushoutFromMatch witness)
+ graphMorphismWeight (pbpoComplementBorrowedLeg witness)
+ graphMorphismWeight (pbpoComplementResidualLeg witness)
graphPBPOComplementWitnessShapeWeight :: PBPOComplementWitness GraphCategory -> Int
graphPBPOComplementWitnessShapeWeight witness =
graphObjectShapeWeight (pbpoComplementPullbackObject witness)
+ graphMorphismShapeWeight (pbpoComplementPullbackToBorrowed witness)
+ graphMorphismShapeWeight (pbpoComplementPullbackToMatch witness)
+ graphObjectShapeWeight (pbpoComplementPushoutObject witness)
+ graphMorphismShapeWeight (pbpoComplementPushoutFromComplement witness)
+ graphMorphismShapeWeight (pbpoComplementPushoutFromMatch witness)
+ graphMorphismShapeWeight (pbpoComplementBorrowedLeg witness)
+ graphMorphismShapeWeight (pbpoComplementResidualLeg witness)
graphObjectShapeWeight :: GraphObject -> Int
graphObjectShapeWeight graph =
graphIdWeight (graphObjectCarrierId graph)
+ graphObjectVertexCount graph
+ graphObjectEdgeCount graph
graphMorphismShapeWeight :: GraphMorphism -> Int
graphMorphismShapeWeight morphism =
graphObjectShapeWeight (graphMorphismSource morphism)
+ graphObjectShapeWeight (graphMorphismTarget morphism)
graphObjectWeight :: GraphObject -> Int
graphObjectWeight graph =
graphIdWeight (graphObjectCarrierId graph)
+ denseIntSetWeight (graphObjectVertexSet graph)
+ denseIntSetWeight (graphObjectEdgeSet graph)
graphMorphismWeight :: GraphMorphism -> Int
graphMorphismWeight morphism =
graphObjectWeight (graphMorphismSource morphism)
+ graphObjectWeight (graphMorphismTarget morphism)
graphIdWeight :: GraphId -> Int
graphIdWeight =
unGraphId