From 54595f2031f5910ce9c351157d1333fcbbc38a51 Mon Sep 17 00:00:00 2001 From: Philipp Seifer Date: Thu, 26 Aug 2021 15:21:49 +0200 Subject: [PATCH] Add complete paper examples --- paper-example/example1.progs | 3 +++ paper-example/example1_fixed.progs | 3 +++ paper-example/example4.progs | 3 +++ paper-example/example4_fixed.progs | 3 +++ paper-example/example5.progs | 8 +++++++ paper-example/example6.progs | 4 ++++ paper-example/example6_fixed.progs | 4 ++++ paper-example/graph.lp | 6 +++--- paper-example/shapes.progs | 7 ------ paper-example/shapes1.progs | 3 --- paper-example/shapes2.progs | 3 --- progs.py | 2 +- src/grammar.ebnf | 12 +++++++++-- src/progs.lp | 34 ++++++++++++++++++------------ src/shapeTranspiler.py | 22 +++++++++++++++++-- 15 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 paper-example/example1.progs create mode 100644 paper-example/example1_fixed.progs create mode 100644 paper-example/example4.progs create mode 100644 paper-example/example4_fixed.progs create mode 100644 paper-example/example5.progs create mode 100644 paper-example/example6.progs create mode 100644 paper-example/example6_fixed.progs delete mode 100644 paper-example/shapes.progs delete mode 100644 paper-example/shapes1.progs delete mode 100644 paper-example/shapes2.progs diff --git a/paper-example/example1.progs b/paper-example/example1.progs new file mode 100644 index 0000000..58ee138 --- /dev/null +++ b/paper-example/example1.progs @@ -0,0 +1,3 @@ +NODE employeeShape [:employee] { + :person +}; \ No newline at end of file diff --git a/paper-example/example1_fixed.progs b/paper-example/example1_fixed.progs new file mode 100644 index 0000000..e58ed88 --- /dev/null +++ b/paper-example/example1_fixed.progs @@ -0,0 +1,3 @@ +NODE employeeShape [:employee] { + :employee +}; \ No newline at end of file diff --git a/paper-example/example4.progs b/paper-example/example4.progs new file mode 100644 index 0000000..be79a6a --- /dev/null +++ b/paper-example/example4.progs @@ -0,0 +1,3 @@ +NODE s1 [:employee] { + >= 1 :colleagueOf.:person +}; \ No newline at end of file diff --git a/paper-example/example4_fixed.progs b/paper-example/example4_fixed.progs new file mode 100644 index 0000000..6783054 --- /dev/null +++ b/paper-example/example4_fixed.progs @@ -0,0 +1,3 @@ +NODE s1 [:employee] { + >= 1 :colleagueOf.:employee +}; \ No newline at end of file diff --git a/paper-example/example5.progs b/paper-example/example5.progs new file mode 100644 index 0000000..627b23d --- /dev/null +++ b/paper-example/example5.progs @@ -0,0 +1,8 @@ +NODE s1 [BOTTOM] { + >= 1 :colleagueOf.:person +}; + +NODE s2 [name = "Gareth Keenan"] { + >= 2 role.string & + s1 +}; \ No newline at end of file diff --git a/paper-example/example6.progs b/paper-example/example6.progs new file mode 100644 index 0000000..8dd25c6 --- /dev/null +++ b/paper-example/example6.progs @@ -0,0 +1,4 @@ +EDGE s3 [:worksFor] { + << :person & + >= 1 since . = 2020 +}; \ No newline at end of file diff --git a/paper-example/example6_fixed.progs b/paper-example/example6_fixed.progs new file mode 100644 index 0000000..1ecd71c --- /dev/null +++ b/paper-example/example6_fixed.progs @@ -0,0 +1,4 @@ +EDGE s3 [:worksFor] { + << :employee & + (>= 1 since . = 2020 | >= 1 since . = 1970) +}; \ No newline at end of file diff --git a/paper-example/graph.lp b/paper-example/graph.lp index 847fc31..4f8c877 100644 --- a/paper-example/graph.lp +++ b/paper-example/graph.lp @@ -9,7 +9,6 @@ edge(102, 203, 101). % Define labels for nodes and edges. label(100, person). -label(102, person). label(100, employee). label(102, employee). label(101, company). @@ -27,6 +26,7 @@ property(100, name, string("Tim Canterbury")). property(100, age, integer(30)). property(101, name, string("Wernham Hogg")). property(102, name, string("Gareth Keenan")). +property(102, role, string("sales")). +property(102, role, string("team leader")). property(203, since, integer(2020)). -property(200, since, integer(1970)). -property(200, since, integer(2007)). \ No newline at end of file +property(200, since, integer(1970)). \ No newline at end of file diff --git a/paper-example/shapes.progs b/paper-example/shapes.progs deleted file mode 100644 index f18c82b..0000000 --- a/paper-example/shapes.progs +++ /dev/null @@ -1,7 +0,0 @@ -NODE employeeShape [:employee] { - >= 1 worksForShape -}; - -EDGE worksForShape [BOTTOM] { - :worksFor -}; \ No newline at end of file diff --git a/paper-example/shapes1.progs b/paper-example/shapes1.progs deleted file mode 100644 index 7c6aafe..0000000 --- a/paper-example/shapes1.progs +++ /dev/null @@ -1,3 +0,0 @@ -NODE s1 [:employee] { - >= 1 :colleagueOf . :person -}; diff --git a/paper-example/shapes2.progs b/paper-example/shapes2.progs deleted file mode 100644 index 705e620..0000000 --- a/paper-example/shapes2.progs +++ /dev/null @@ -1,3 +0,0 @@ -NODE s1 [:employee] { - >= 1 :colleagueOf . :person -} diff --git a/progs.py b/progs.py index 3b31e34..6d56b65 100755 --- a/progs.py +++ b/progs.py @@ -15,7 +15,7 @@ # Basic setup. ap = argparse.ArgumentParser(prog='ProGS', - description='Run validation on property graphs. For basic validation use \'validate\' mode.', + description='Run validation on property graphs. For standard validation use \'validate\' mode.', epilog='Philipp Seifer @ https://github.com/softlang/progs') ap.version = '0.1' ap.add_argument('-v', action='version') diff --git a/src/grammar.ebnf b/src/grammar.ebnf index 6db2b70..b0de72d 100644 --- a/src/grammar.ebnf +++ b/src/grammar.ebnf @@ -5,7 +5,8 @@ edgeshape : "EDGE" shape "[" edgetarget "]" "{" edgeconstraint "}" ";" nodetarget : ":" label | NUMBER -> nid | "BOTTOM" -> bot - | property -> property + | property "=" value -> propvalue + | property -> propertytarget ?nodeconstraint : nodeconstraint_or ?nodeconstraint_or : [nodeconstraint_or "|"] nodeconstraint_and @@ -33,11 +34,13 @@ path : ":" label predicate : "string" -> string | "int" -> int + | "=" value -> eqvalue edgetarget : ":" label | NUMBER -> eid | "BOTTOM" -> bot - | property -> property + | property "=" value -> propvalue + | property -> propertytarget ?edgeconstraint : edgeconstraint_or ?edgeconstraint_or : [edgeconstraint_or "|"] edgeconstraint_and @@ -54,6 +57,9 @@ edgeconstraint_basic : "TOP" -> top | ">>" nodeconstraint_basic -> right | "(" edgeconstraint ")" +?value : "\"" STRING "\"" -> stringvalue + | NUMBER -> intvalue + comp : "<=" -> le | ">=" -> ge | ">" -> gr @@ -68,6 +74,8 @@ labelref : WORD WORD : LCASE_LETTER CHAR+ CHAR : LETTER | DIGIT | "_" NUMBER : DIGIT+ +SCHAR : CHAR | WS +STRING : SCHAR+ COMMENT : "%" /(.)*/ NEWLINE diff --git a/src/progs.lp b/src/progs.lp index 241ef27..2c1196a 100644 --- a/src/progs.lp +++ b/src/progs.lp @@ -1,4 +1,4 @@ -% -- Data Model -- +% -- data model -- node(X) :- edge(X,_,_). node(X) :- edge(_,_,X). @@ -7,7 +7,7 @@ edge(X) :- edge(_,X,_). labels(L) :- label(_, L). properties(P) :- property(_, P, _). -% -- Utility -- +% -- utility -- min(yes,yes,yes). min(yes,no,no). @@ -19,17 +19,19 @@ min(maybe,maybe,maybe). min(no,maybe,no). min(maybe,no,no). -% -- Core -- +% -- core -- nodeshape(S) :- nodeshape(S,_,_). edgeshape(S) :- edgeshape(S,_,_). targetN(N,S) :- nodeshape(S,_,label(L)), label(N,L). targetN(N,S) :- nodeshape(S,_,hasProperty(K)), property(N,K,_). +targetN(N,S) :- nodeshape(S,_,hasPropertyValue(K,V)), property(N,K,V). targetN(N,S) :- nodeshape(S,_,node(N)). targetE(E,S) :- edgeshape(S,_,label(L)), label(E,L). targetE(E,S) :- edgeshape(S,_,hasProperty(K)), property(E,K,_). +targetE(E,S) :- edgeshape(S,_,hasPropertyValue(K,V), property(E,K,V)). targetE(E,S) :- edgeshape(S,_,edge(E)). :- targetN(N,S), not assignN(N,S,yes). @@ -89,11 +91,15 @@ satisfiesN(N, negate(C), yes) :- node(N), constraint(negate(C)), satisfiesN(N,C,no). satisfiesN(N, negate(C), no) :- node(N), constraint(negate(C)), satisfiesN(N,C,yes). +satisfiesN(N, negate(C), maybe) :- node(N), constraint(negate(C)), + satisfiesN(N, C, maybe). satisfiesE(E, negate(C), yes) :- edge(E), constraint(negate(C)), satisfiesE(E,C,no). satisfiesE(E, negate(C), no) :- edge(E), constraint(negate(C)), satisfiesE(E,C,yes). +satisfiesE(E, negate(C), maybe) :- edge(E), constraint(negate(C)), + satisfiesE(E, C, maybe). % -- and -- @@ -127,7 +133,9 @@ countNC(N,P,NC,C) :- node(N), path(P), constraint(NC), countNoNC(N,P,NC,C) :- node(N), path(P), constraint(NC), #count { Y: path(N,Y,P), satisfiesN(Y,NC,no) } = C. -% -- compare -- TODO +% -- compare -- + +% not yet supported % -- greaterEqE -- @@ -164,17 +172,17 @@ satisfiesE(E,countProp(K,isString,I),no) :- edge(E), constraint(countProp(K,isSt satisfiesE(E,countProp(K,isInteger,I),yes) :- edge(E), constraint(countProp(K,isInteger,I)), #count { V: property(E,K,integer(V)) } >= I. satisfiesE(E,countProp(K,isInteger,I),no) :- edge(E), constraint(countProp(K,isInteger,I)), #count { V: property(E,K,integer(V)) } < I. -satisfiesN(N,countProp(K,equals(R),I),yes) :- node(N), constraint(countProp(K,equals(R),I)), #count { V: property(N,K,integer(V)), V == R } >= I. -satisfiesN(N,countProp(K,equals(R),I),no) :- node(N), constraint(countProp(K,equals(R),I)), #count { V: property(N,K,integer(V)), V == R } < I. -satisfiesN(N,countProp(K,equals(R),I),yes) :- node(N), constraint(countProp(K,equals(R),I)), #count { V: property(N,K,string(V)), V == R } >= I. -satisfiesN(N,countProp(K,equals(R),I),no) :- node(N), constraint(countProp(K,equals(R),I)), #count { V: property(N,K,string(V)), V == R } < I. +% - + +satisfiesN(N,countProp(K,eq(R),I),yes) :- node(N), constraint(countProp(K,eq(R),I)), #count { V: property(N,K,V), V == R } >= I. +satisfiesN(N,countProp(K,eq(R),I),no) :- node(N), constraint(countProp(K,eq(R),I)), #count { V: property(N,K,V), V == R } < I. + +satisfiesE(E,countProp(K,eq(R),I),yes) :- edge(E), constraint(countProp(K,eq(R),I)), #count { V: property(E,K,V), V == R } >= I. +satisfiesE(E,countProp(K,eq(R),I),no) :- edge(E), constraint(countProp(K,eq(R),I)), #count { V: property(E,K,V), V == R } < I. -satisfiesE(E,countProp(K,equals(R),I),yes) :- edge(E), constraint(countProp(K,equals(R),I)), #count { V: property(E,K,integer(V)), V == R } >= I. -satisfiesE(E,countProp(K,equals(R),I),no) :- edge(E), constraint(countProp(K,equals(R),I)), #count { V: property(E,K,integer(V)), V == R } < I. -satisfiesE(E,countProp(K,equals(R),I),yes) :- edge(E), constraint(countProp(K,equals(R),I)), #count { V: property(E,K,string(V)), V == R } >= I. -satisfiesE(E,countProp(K,equals(R),I),no) :- edge(E), constraint(countProp(K,equals(R),I)), #count { V: property(E,K,string(V)), V == R } < I. +% -- compareValues -- -% -- compareValues -- TODO +% not yet supported % -- equals -- diff --git a/src/shapeTranspiler.py b/src/shapeTranspiler.py index 52724af..83710b2 100755 --- a/src/shapeTranspiler.py +++ b/src/shapeTranspiler.py @@ -28,9 +28,12 @@ def nid(self, n): def bot(self, b): return 'bottom' - def property(self, k): + def propertytarget(self, k): return "hasProperty({})".format(k[0]) + def propvalue(sekf, kv): + return "hasPropertyValue({},{})".format(kv[0], kv[1]) + def shaperef(self, s): c = 'shapeRef({})'.format(s[0]) constraint_store.add(c) @@ -71,7 +74,13 @@ def nodeconstraint_and(self, items): return c def nodeconstraint_or(self, items): - c = 'negate(and(negate({}),negate({})))'.format(items[0],items[1]) + c1 = 'negate({})'.format(items[0]) + c2 = 'negate({})'.format(items[1]) + c3 = 'and({},{})'.format(c1,c2) + c = 'negate({})'.format(c3) + constraint_store.add(c1) + constraint_store.add(c2) + constraint_store.add(c3) constraint_store.add(c) return c @@ -171,12 +180,21 @@ def countprop(self, p): constraint_store.add(c) return c + def eqvalue(self, v): + return "eq({})".format(v[0]) + def string(self, s): return "isString" + def stringvalue(self, s): + return "string(\"{}\")".format(s[0]) + def int(self, s): return "isInteger" + def intvalue(self, i): + return "integer({})".format(i[0]) + def compare(self, ps): c = 'compare({},{})'.format(ps[0],ps[1]) constraint_store.add(c)