Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions src/GraphQueries/GraphQueries.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
grammar GraphQueries;

script : (stmt SEMI)* EOF ;

stmt : KW_CONNECT KW_TO STRING
| KW_LIST KW_ALL? STRING?
| select_stmt
| named_pattern
;

named_pattern : NT_NAME OP_EQ pattern ;

select_stmt : KW_SELECT func KW_FROM from_expr KW_WHERE where_expr alg? ;

func : KW_GET
| KW_COUNT
| KW_EXISTS
;

alg : KW_USING KW_HELLINGS
| KW_USING KW_MATRICES
| KW_USING KW_TENSORS
;

from_expr : graph_expr? STRING
;

where_expr : LBR v_expr RBR OP_MINUS pattern OP_MINUS OP_GR LBR v_expr RBR ;

v_expr : INT
| UNDERSCORE
;

graph_expr : STRING
| KW_INTERSEC LBR graph_expr COMMA graph_expr RBR
| KW_UNION LBR graph_expr COMMA graph_expr RBR
| KW_COMPL LBR graph_expr RBR
;

pattern : elem
| elem MID pattern
;

elem : seq
| LBR RBR
;

seq : seq_elem
| seq_elem seq
;

seq_elem : prim_pattern
| prim_pattern OP_STAR
;

prim_pattern : SYMB
| NT_NAME
| LBR pattern RBR
;

LBR : '(' ;
RBR : ')' ;
COMMA : ',' ;
SEMI : ';' ;
MID : '|' ;
DOT : '.' ;
UNDERSCORE : '_' ;
OP_STAR : '*' ;
OP_MINUS : '-' ;
OP_GR : '>' ;
OP_EQ : '=' ;
KW_SELECT : 'select' ;
KW_GET : 'get' ;
KW_COUNT : 'count' ;
KW_EXISTS : 'exists' ;
KW_FROM : 'from' ;
KW_WHERE : 'where' ;
KW_LIST : 'list' ;
KW_ALL : 'all' ;
KW_CONNECT : 'connect' ;
KW_TO : 'to' ;
KW_USING : 'using' ;
KW_HELLINGS : 'hellings' ;
KW_MATRICES : 'matrices' ;
KW_TENSORS : 'tensors' ;
KW_INTERSEC : 'intersec' ;
KW_UNION : 'union' ;
KW_COMPL : 'compl' ;
INT : '0'
| [1-9][0-9]*
;
SYMB : [a-z]+ ;
NT_NAME : [A-Z]+ ;
STRING : '[' ([a-zA-Z]|[0-9]|('\\' | '-' | '_' | ' ' | '/' | '.' | ',' | ':'))* ']' ;
WS : [ \r\n\t]+ -> skip ;
220 changes: 220 additions & 0 deletions src/GraphQueries/MyGraphQueriesVisitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#!/usr/bin/env python3
import os
from collections import defaultdict
from antlr4 import *
from chomsky import to_weak_CNF
from algebra import matrix_alg
from algebra import tensor_alg
from chomsky import get_new_nonterm
from cyk import parse_graph
from cyk import Hellings
from graph_lang import *
if __name__ is not None and "." in __name__:
from .GraphQueriesParser import GraphQueriesParser
else:
from GraphQueriesParser import GraphQueriesParser

# This class defines a complete generic visitor for a parse tree produced by GraphQueriesParser.

class MyGraphQueriesVisitor(ParseTreeVisitor):
def __init__(self, parent=None):
self.addr = ""
self.prods = defaultdict(str)


def get_addr(self):
return self.addr


def get_prods(self):
return self.prods.items()


def get_res(self, start, finish, nonterm, matrix, n):
res = []
if start == "_" and finish == "_":
for i in range(n):
for j in range(n):
if matrix[nonterm][i, j]:
res.append((i, j))
elif start == "_":
for i in range(n):
if matrix[nonterm][i, int(finish)]:
res.append((i, int(finish)))
elif finish == "_":
for i in range(n):
if matrix[nonterm][int(start), i]:
res.append((int(start), i))
else:
if matrix[nonterm][int(start), int(finish)]:
res.append((int(start), int(finish)))

return res


def select_get_tensors(self, start, finish, pattern, graph):
nonterms = self.prods.keys()
add_nonterm = get_new_nonterm("S", nonterms)
_, matrix, _, n = tensor_alg(list(self.prods.items()) + [(add_nonterm, pattern)], graph)
return self.get_res(start, finish, add_nonterm, matrix, n)


def select_get(self, start, finish, pattern, graph, alg):
nonterms = self.prods.keys()
add_nonterm = get_new_nonterm("S", nonterms)
new_prods = []
for nonterm in self.prods.keys():
lst = self.prods[nonterm].split(" | ")
new_prods += [(nonterm, element.split()) for element in lst]
new_prods = to_weak_CNF(new_prods + [(add_nonterm, pattern.split())], add_nonterm)
if alg == "hellings":
res = Hellings(new_prods, graph)
else:
res = matrix_alg(new_prods, graph)
ans = []
if start == "_" and finish == "_":
for nonterm, u, v in res:
if nonterm == add_nonterm:
ans.append((u, v))
elif start == "_":
for nonterm, u, v in res:
if nonterm == add_nonterm and v == int(finish):
ans.append((u, v))
elif finish == "_":
for nonterm, u, v in res:
if nonterm == add_nonterm and u == int(start):
ans.append((u, v))
else:
for nonterm, u, v in res:
if nonterm == add_nonterm and u == int(start) and v == int(finish):
ans.append((u, v))

return ans


def select_get_graph_lang(self, start, finish, pattern, graph, automata):
nonterms = self.prods.keys()
add_nonterm = get_new_nonterm("S", nonterms)
_, matrix1, _, n1 = tensor_alg(list(self.prods.items()) + [(add_nonterm, pattern)], graph)
_, matrix2, _, n2 = tensor_alg([(add_nonterm, "")], graph, automata)
res1 = self.get_res(start, finish, add_nonterm, matrix1, n1)
res2 = self.get_res(start, finish, add_nonterm, matrix2, n2)

return sorted(list(set(res1) & set(res2)))


# Visit a parse tree produced by GraphQueriesParser#script.
def visitScript(self, ctx:GraphQueriesParser.ScriptContext):
self.visitChildren(ctx)


# Visit a parse tree produced by GraphQueriesParser#stmt.
def visitStmt(self, ctx:GraphQueriesParser.StmtContext):
if ctx.getChild(0).getText() == "connect":
self.addr = ctx.STRING().getText()[1:-1]
elif ctx.getChild(0).getText() == "list":
if ctx.getChild(1).getText() == "all":
if ctx.getChildCount() == 3:
path = ctx.STRING().getText()[1:-1]
else:
path = self.addr
for file in sorted(os.listdir(path)):
print(open(os.path.join(path, file), "r").read() + "\n")
else:
filename = ctx.STRING().getText()[1:-1]
labels = set()
with open(os.path.join(filename)) as file:
for line in file.readlines():
labels.add(line.split()[1])
print(" ".join(sorted(list(labels))))
else:
self.visitChildren(ctx)


# Visit a parse tree produced by GraphQueriesParser#named_pattern.
def visitNamed_pattern(self, ctx:GraphQueriesParser.Named_patternContext):
nonterm = ctx.NT_NAME().getText()
if self.prods[nonterm]:
self.prods[nonterm] += " | " + self.visitPattern(ctx.pattern())
else:
self.prods[nonterm] = self.visitPattern(ctx.pattern())


# Visit a parse tree produced by GraphQueriesParser#select_stmt.
def visitSelect_stmt(self, ctx:GraphQueriesParser.Select_stmtContext):
if ctx.from_expr().getChildCount() == 1:
pattern = self.visitPattern(ctx.where_expr().pattern())
if ctx.getChildCount() == 6 or (ctx.getChildCount() == 7 and ctx.alg().getChild(1).getText() == "tensors"):
res = self.select_get_tensors(ctx.where_expr().getChild(1).getText(),
ctx.where_expr().getChild(8).getText(), pattern,
parse_graph(ctx.from_expr().STRING().getText()[1:-1]))
else:
res = self.select_get(ctx.where_expr().getChild(1).getText(), ctx.where_expr().getChild(8).getText(),
pattern, parse_graph(ctx.from_expr().STRING().getText()[1:-1]), ctx.alg().getChild(1).getText())
else:
pattern = self.visitPattern(ctx.where_expr().pattern())
automata = self.visitGraph_expr(ctx.from_expr().graph_expr())
res = self.select_get_graph_lang(ctx.where_expr().getChild(1).getText(), ctx.where_expr().getChild(8).getText(),
pattern, parse_graph(ctx.from_expr().STRING().getText()[1:-1]), automata)
if ctx.func().getText() == "exists":
if res:
print("exists")
else:
print("does not exist")
elif ctx.func().getText() == "count":
print(len(res))
else:
for u, v in res:
print(str(u) + " " + str(v))


# Visit a parse tree produced by GraphQueriesParser#graph_expr.
def visitGraph_expr(self, ctx: GraphQueriesParser.Graph_exprContext):
if ctx.getChildCount() == 1:
return build_automata_from_graph(ctx.STRING().getText()[1:-1])
elif ctx.getChild(0).getText() == "intersec":
return intersec(self.visitGraph_expr(ctx.getChild(2)), self.visitGraph_expr(ctx.getChild(4)))
elif ctx.getChild(0).getText() == "union":
return union(self.visitGraph_expr(ctx.getChild(2)), self.visitGraph_expr(ctx.getChild(4)))
else:
return compl(self.visitGraph_expr(ctx.getChild(2)))


# Visit a parse tree produced by GraphQueriesParser#pattern.
def visitPattern(self, ctx:GraphQueriesParser.PatternContext):
if ctx.getChildCount() == 3:
return self.visitElem(ctx.elem()) + " " + ctx.MID().getText() + " " + self.visitPattern(ctx.pattern())
return self.visitElem(ctx.elem())


# Visit a parse tree produced by GraphQueriesParser#elem.
def visitElem(self, ctx:GraphQueriesParser.ElemContext):
if ctx.getChildCount() == 1:
return self.visitSeq(ctx.seq())
else:
return "eps"


# Visit a parse tree produced by GraphQueriesParser#seq.
def visitSeq(self, ctx:GraphQueriesParser.SeqContext):
if ctx.getChildCount() == 2:
return self.visitSeq_elem(ctx.seq_elem()) + " " + self.visitSeq(ctx.seq())
else:
return self.visitSeq_elem(ctx.seq_elem())


# Visit a parse tree produced by GraphQueriesParser#seq_elem.
def visitSeq_elem(self, ctx:GraphQueriesParser.Seq_elemContext):
if ctx.getChildCount() == 2:
return self.visitPrim_pattern(ctx.prim_pattern()) + ctx.getChild(1).getText()
return self.visitPrim_pattern(ctx.prim_pattern())


# Visit a parse tree produced by GraphQueriesParser#prim_pattern.
def visitPrim_pattern(self, ctx:GraphQueriesParser.Prim_patternContext):
if ctx.getChildCount() == 3:
return ctx.LBR().getText() + self.visitPattern(ctx.pattern()) + ctx.RBR().getText()
else: return ctx.getChild(0).getText()


del GraphQueriesParser
Loading