verites / verigraph Goto Github PK
View Code? Open in Web Editor NEWSoftware specification and verification system based on graph rewriting
Home Page: https://verites.github.io/verigraph/
License: Apache License 2.0
Software specification and verification system based on graph rewriting
Home Page: https://verites.github.io/verigraph/
License: Apache License 2.0
While writing some tests, I found an abnormal behaviour on the equality tests of Graph Morphisms, the problem seems to be w.r.t. Relations Equality Comparison.
spec :: Spec
spec = describe "Graph Morphism API" $ do
describe "removeNodeFromCodomain" $ do
it "Should remove node without incident edges" $ do
(nodeRelation $ removeNodeFromCodomain 3 g1) `shouldBe` (nodeRelation g4)
Graph.GraphMorphism, Graph Morphism API, removeNodeFromCodomain, Should remove node without incident edges
expected: Relation {domain = [1,2,4,3], codomain = [1,2,4], mapping = fromList [(1,[1]),(2,[2]),(4,[4])]}
but got: Relation {domain = [1,2,3,4], codomain = [1,2,4], mapping = fromList [(1,[1]),(2,[2]),(3,[]),(4,[4])]}
g1' :: Graph (Maybe a) (Maybe b)
g1' = build [1,2,3,4] [(1,1,2)]
g2' :: Graph (Maybe a) (Maybe b)
g2' = build [1,2,4] [(1,1,2)]
g1 :: GraphMorphism (Maybe a) (Maybe b)
g1 = buildGraphMorphism g1' g1' [(1,1),(2,2),(3,3),(4,4)] [(1,1)]
g4 :: GraphMorphism (Maybe a) (Maybe b)
g4 = buildGraphMorphism g1' g2' [(1,1),(2,2),(4,4)] [(1,1)]
The API of module Graph.Graph
forces frequent lookups into the association lists, which probably incurs a performance penalty. Also, its functions often return Maybe
s where the result could be guaranteed to exist.
In order to reduce these issues, a notion of "node context" could be introduced, which allows the user to access the incident edges of a node. This would make the lookups implicit, and the well-formedness of the graphs ensures that such lookups do not fail.
The following is a sketch of the additions/changes to Graph.Graph
module
data Node n =
Node NodeId (Maybe n)
data Edge e =
Edge EdgeId NodeId NodeId (Maybe e)
type NodeInContext n e =
(Node n, NodeContext n e)
type EdgeInContext n e =
(NodeInContext n e, Edge e, NodeInContext n e)
-- The constructor for NodeContext is not exported.
data NodeContext n e =
NodeContext NodeId (Graph n e)
lookupNodeInContext :: NodeId -> Graph n e -> Maybe (NodeContext n e)
incidentEdges :: NodeContext -> [EdgeInContext n e]
incomingEdges :: NodeContext -> [EdgeInContext n e]
outgoingEdges :: NodeContext -> [EdgeInContext n e]
As an example of usage, this is an implementation of depth-first search using the contexts.
depthFirstSearch :: NodeInContext n e -> [Node n]
depthFirstSearch initialNode =
search IntSet.empty [initialNode]
where
search _ [] = []
search visitedNodes ((node, context) : rest) =
if node `IntSet.member` visitedNodes then
search visitedNodes rest
else
let
nextNodes =
[ target | (_, _, target) <- outgoingEdges context ]
in
node :: search (IntSet.insert (nodeId node) visitedNodes) (nextNodes ++ rest)
The method induceSpanMorphism
of the FindMorphism
class will sometimes generate an invalid morphism, since the desired morphism doesn't always exist.
This should be documented, or even better, it should return Nothing
when the morphism doesn't exist.
Currently, the payloads of graph nodes and edges are optional. That is, in a Graph n e
, nodes contain payloads of type Maybe n
and edges, of type Maybe e
. There is currently, however, no use for these payloads in Verigraph, not even to allow metadata such as graph layout (since payloads are not handled and propagated by pullbacks, pushouts, overlappings and similar operations).
One of the possible uses would be to store attributes and typing information, which would reduce the number of dictionary lookups necessary to handle typed attributed graphs, simplifying code and improving performance. This, however, is not possible with optional payloads, since all nodes and edges need to have this information.
In order to allow this, graphs would need to have mandatory payloads. That is, in a Graph n e
, nodes would contain payloads of type n
and edges, of type e
. Then, typed attributed graphs could be implemented simply as follows.
import qualified Graph as G
type AttributedGraph n e =
G.Graph (NodeType, Map AttrName AttrValue, n) (EdgeType, Map AttrName AttrValue, e)
type Node n =
G.Node (NodeType, Map AttrName AttrValue, n)
type Edge e =
G.Edge (EdgeType, Map AttrName AttrValue, e)
nodeType :: Node n -> NodeType
nodeType = fst . G.nodeInfo
edgeType :: Edge n -> EdgeType
edgeType = fst . G.edgeInfo
nodeInfo :: Node n -> n
nodeInfo = third . G.nodeInfo
edgeInfo :: Edge e -> e
edgeInfo = third . G.edgeInfo
This implementation pattern has the following advantages:
A single lookup gives all information about a node or edge, simplifying code and improving efficiency.
Most of the Graph API would be immediately applicable to specialized graph types, without the need for separate functions as is currently done in for TypedGraph
s
First, change the implementation of Graph
so its has mandatory payloads. The impact of this change in the rest of Verigraph could be handled in two ways, based on Graph () ()
(unit-based) or on Graph (Maybe n) (Maybe e)
(maybe-based).
Since no part of verigraph currently uses the payloads, they could be replaced with unit types whenever they are "ignored" by functions. We'd have, for example:
insertNode :: NodeId -> Graph () e -> Graph () e
insertNodeWithPayload :: NodeId -> n -> Graph n e -> Graph n e
instance Morphism (GraphMorphism () ())
instance Morphism (TypedGraphMorphism () ())
Alternatively, we could displace the assumption of optional payloads to the function signature. That is, whenever Nothing
is required to be a possible node payload, the type signature contains Graph (Maybe n) e
(analogously for edges). We'd have, for example:
insertNode :: NodeId -> Graph (Maybe n) e -> Graph (Maybe n) e
insertNodeWithPayload :: NodeId -> n -> Graph n e -> Graph n e
instance Morphism (GraphMorphism (Maybe n) (Maybe e))
instance Morphism (TypedGraphMorphism (Maybe n) (Maybe e))
Allow user-defined node/edge types in symbolic graphs. Allow user-defined attributes for each of these types.
Currently, some of the tests are using plain HUnit and some are using Hspec with HUnit and QuickCheck. We should unify all tests under a single style.
Sometimes it would be useful to associate some metadata to nodes and edges, that is used e.g. for the GUI or documentation purposes, and have it properly handled and propagated to outputs.
A simple example are the positions of nodes. It could be useful for critical pairs to have a (preliminary) node layout that is based on the node layout of the rules. This layout would then be refined by some algorithm in the GUI.
In order to do this, we'd probably need to include this metadata into the payloads of nodes and edges. We'd also need to figure out how to properly handle these payloads in basic categorial operations such as pullbacks, pushouts, overlappings, etc. This would probably involve having a type class with the necessary operations.
A first suggestion would be to use the Monoid
class, which describes types that have an "empty" value and can be arbitrarily combined. Then any elements created from scratch would have the "empty metadata, elements created from a single other element would have the metadata copied and elements created from multiple other elements (e.g. in an overlapping or pushout) would have the metadata combined.
In the example of using positions, the following type could be used as metadata:
type Position
= Position Float Float
| NoPosition
instance Monoid Position where
mempty = NoPosition
mappend NoPosition p = p
mappend p NoPosition = p
mappend (Position x1 y1) (Position x2 y2) = Position ((x1+x2)/2) ((y1+y2)/2)
We still have to check if Monoid
is enough, and how exactly the metadata is propagated by the primitive operations.
Have a command line program that calculates critical pairs and writes them to a CPX file.
Write the unit tests for the concurrent rules calculation functionality
Verigraph does not export the rule sequences of the original input GGX file to the output one.
Some categories have different classes of morphism, not just epi/mono/iso. In particular, some categories are adhesive with respect to a subclass N of monomorphisms. Some will further restrict the morphisms which are allowed in productions.
An example is Symbolic Graph Transformation, where rules must be monomorphic in the graph component and isomorphic in the attribute component.
These are not contemplated in the current architecture.
It would make sense for graphs and typed graphs to have a similar interface (after all, they are both graphs). Therefore, a type class might be useful to unify them.
The function removeNodeFromDomain
from the GraphMorphism
module does not remove a node that has incident edges, which is the default behaviour of verigraph in order to not generate invalid structures.
However, it still removes the mapping of the node to its image, which may lead to invalid graphs.
Investigate the implementation of multiplicities in the type graph and the corresponding restrictions over the grammar and the analyses provided by verigraph.
Remove calculatePushout
of AdhesiveHLR.
Move the pushout implementation to Cocomplete
Type Class.
Currently, the function valid returns a Bool
, which is not helpful when we need to fix a malformed value. It should be changed to return a Maybe String
, producing appropriate error messages. We must also think about how to handle the context in which errors occur.
JSON as input/output format will make integration between verigraph and other tools (including @Verites/verigraph-gui ) easier.
So, we need define a JSON format to verigraph.
With the changes introduced on the api by #11 there are a big number of warnings from the compiler. We should make an effort to resolve them as soon as possible, since this makes logs difficult to read.
CPA process can be easily parallelized, and Haskell offers good options...
Refactor the Morphism
type class, renaming it to FinitaryCategory
to better match its responsabilities.
At the same time, implement @ggazzi's suggestion of using a Context Monad to store important information about the category, such as the type graph of a TGraph and the type graph and NAC strategy of a TSpan.
Morphism
to FinitaryCategory
compose
and add an alias (<&>)
FindMorphism
into FinitaryCategory
Verigraph does not import/export attributes from/to GGX file.
It will allow Verigraph to manipulate grammars with attributes without changing them.
Implement a data type for (untyped) symbolic graphs and morphisms, including instances of Morphism
, FindMorphism
, EpiPair
, AdhesiveHLR
.
The base algebra should support only integers. The graphs are untyped, and each node contains a single integer attribute. Edges have no attributes.
Verigraph does not support GGX files that contains different edge types with the same ID but different node types for source and target.
The following draft should be finished and published to Coding Style Guide
This is a short document based on Johan Tibell's style guide describing the preferred coding style for this project. Some of these rules can be enforced by stylish-haskell, using the configuration file in the project root.
Maximum line length is 100 characters. "Going over is not the end of the world, but consider refactoring before you decide a line really must be longer."¹
Tabs are illegal. Use spaces for indenting. Always indent to multiples of two.
¹ As in the Elm style guide
Creating test cases with typed graphs is currently a time consuming, manual work. We should probably find a better way to do this.
Wishlist:
Create a Complete
Type Class with be basic operations equalizer
and product
, similar to Cocomplete and AdhesiveHLR.
Move the pullback
implementation to it.
There are some operations spread among the modules of DPO and AdhesiveHLR that do not appear to be in the right place. Specially regarding NACs and rewritting. Such as:
DPO:
nacDownwardShift
AdhesiveHLR:
MatchRestriction
matchRestrictionToMorphismType
NacSatisfaction
Since we are in a process of refactoring the projects architecture, should we create new specific modules for?
Category
moduleMatchRestriction
to MorphismType
.Related Issues:
There is a cyclic dependency between XML.GGXReader
and XML.GGXSndOrderReader
. It should be removed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.