Skip to content

Commit

Permalink
Clingraph svg
Browse files Browse the repository at this point in the history
  • Loading branch information
susuhahnml committed Feb 23, 2024
1 parent 81c37ba commit 1d86438
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 31 deletions.
6 changes: 6 additions & 0 deletions examples/basic/last_supoprt.lp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
a:-b.
a:-c.
:- not a.
:-c.
{b}.
{c}.
8 changes: 8 additions & 0 deletions examples/sudoku/encoding_extra.lp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{assign((Row, Col), Value) : Value = 1..9} = 1 :- Row = 1..9; Col = 1..9.
:- block(Block, Cell); block(Block, Cell'), Cell != Cell'; assign(Cell, Value), assign(Cell', Value).
:- given(Cell, Value), not assign(Cell, Value).
:- block(Block, Cell'); Value = 1..9; not assign(Cell, Value) : block(Block, Cell).

block((row, Row), (Row, Col)) :- Row = 1..9, Col = 1..9.
block((col, Col), (Row, Col)) :- Row = 1..9, Col = 1..9.
block((sub, Row', Col'), (Row, Col)) :- Row = 1..9; Col = 1..9; Row' = (Row-1) / 3; Col' = (Col-1) / 3.
28 changes: 25 additions & 3 deletions graph.lp
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
link("a(1)","b(1)", "ImEoMSk6LWIoMSk7IF9fcHVzX18ocHJvZ3JhbSwwKS4i").
node("a(1)",true, (support, "ImEoMSk6LWIoMSk7IF9fcHVzX18ocHJvZ3JhbSwwKS4i")).
node("b(1)",true, (support, "ImIoMSkgOi0gX19wdXNfXyhwcm9ncmFtLDEpLiI=")).
input_link(assign((1,1),2),assign((1,1),3), "e2Fzc2lnbigoMSwxKSwxKTsgYXNzaWduKCgxLDEpLDIpOyBhc3NpZ24oKDEsMSksMyk7IGFzc2lnbigoMSwxKSw0KX0gPSAxIDotIDEgPSAxLi40OyAxID0gMS4uNC4=").
input_link(assign((2,4),2),given((2,4),2), "Oi0gZ2l2ZW4oKDIsNCksIDIpLCBub3QgYXNzaWduKCgyLDQpLCAyKS4=").
input_link(assign((1,1),3),given((1,1),3), "Oi0gZ2l2ZW4oKDEsMSksIDMpLCBub3QgYXNzaWduKCgxLDEpLCAzKS4=").
input_link(assign((2,2),2),block((row,2),(2,4)), "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwyKSksICgyLDQpICE9ICgyLDIpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMiksIDIpLg==").
input_link(assign((2,2),2),block((row,2),(2,2)), "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwyKSksICgyLDQpICE9ICgyLDIpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMiksIDIpLg==").
input_link(assign((2,2),2),assign((2,4),2), "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwyKSksICgyLDQpICE9ICgyLDIpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMiksIDIpLg==").
input_link(assign((2,1),2),block((row,2),(2,4)), "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwxKSksICgyLDQpICE9ICgyLDEpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMSksIDIpLg==").
input_link(assign((2,1),2),block((row,2),(2,1)), "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwxKSksICgyLDQpICE9ICgyLDEpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMSksIDIpLg==").
input_link(assign((2,1),2),assign((2,4),2), "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwxKSksICgyLDQpICE9ICgyLDEpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMSksIDIpLg==").
input_link(assign((1,2),2),block((sub,0,0),(2,2)), "Oi0gYmxvY2soKHN1YiwwLDApLCAoMiwyKSk7IDIgPSAxLi40OyBub3QgYXNzaWduKCgyLDIpLDIpOyBub3QgYXNzaWduKCgyLDEpLDIpOyBub3QgYXNzaWduKCgxLDIpLDIpOyBub3QgYXNzaWduKCgxLDEpLDIpLg==").
input_link(assign((1,2),2),assign((2,2),2), "Oi0gYmxvY2soKHN1YiwwLDApLCAoMiwyKSk7IDIgPSAxLi40OyBub3QgYXNzaWduKCgyLDIpLDIpOyBub3QgYXNzaWduKCgyLDEpLDIpOyBub3QgYXNzaWduKCgxLDIpLDIpOyBub3QgYXNzaWduKCgxLDEpLDIpLg==").
input_link(assign((1,2),2),assign((2,1),2), "Oi0gYmxvY2soKHN1YiwwLDApLCAoMiwyKSk7IDIgPSAxLi40OyBub3QgYXNzaWduKCgyLDIpLDIpOyBub3QgYXNzaWduKCgyLDEpLDIpOyBub3QgYXNzaWduKCgxLDIpLDIpOyBub3QgYXNzaWduKCgxLDEpLDIpLg==").
input_link(assign((1,2),2),assign((1,1),2), "Oi0gYmxvY2soKHN1YiwwLDApLCAoMiwyKSk7IDIgPSAxLi40OyBub3QgYXNzaWduKCgyLDIpLDIpOyBub3QgYXNzaWduKCgyLDEpLDIpOyBub3QgYXNzaWduKCgxLDIpLDIpOyBub3QgYXNzaWduKCgxLDEpLDIpLg==").
input_node(block((row,2),(2,1)),true, (support, "YmxvY2soKHJvdywgMiksICgyLCAxKSkgOi0gMiA9IDEuLjQsIDEgPSAxLi40Lg==")).
input_node(block((row,2),(2,2)),true, (support, "YmxvY2soKHJvdywgMiksICgyLCAyKSkgOi0gMiA9IDEuLjQsIDIgPSAxLi40Lg==")).
input_node(block((row,2),(2,4)),true, (support, "YmxvY2soKHJvdywgMiksICgyLCA0KSkgOi0gMiA9IDEuLjQsIDQgPSAxLi40Lg==")).
input_node(block((sub,0,0),(2,2)),true, (support, "YmxvY2soKHN1YiwgMCwgMCksICgyLCAyKSkgOi0gMiA9IDEuLjQ7IDIgPSAxLi40OyAwID0gKDItMSkgLyAyOyAwID0gKDItMSkgLyAyLg==")).
input_node(given((1,1),3),true, (support, "Z2l2ZW4oKDEsMSksIDMpLg==")).
input_node(given((2,4),2),true, (support, "Z2l2ZW4oKDIsNCksIDIpLg==")).
input_node(assign((2,4),2),true, (constraint, "Oi0gZ2l2ZW4oKDIsNCksIDIpLCBub3QgYXNzaWduKCgyLDQpLCAyKS4=",lower_bound)).
input_node(assign((1,1),3),true, (constraint, "Oi0gZ2l2ZW4oKDEsMSksIDMpLCBub3QgYXNzaWduKCgxLDEpLCAzKS4=",lower_bound)).
input_node(assign((2,2),2),false, (constraint, "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwyKSksICgyLDQpICE9ICgyLDIpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMiksIDIpLg==",lower_bound)).
input_node(assign((2,1),2),false, (constraint, "Oi0gYmxvY2soKHJvdywyKSwgKDIsNCkpOyBibG9jaygocm93LDIpLCAoMiwxKSksICgyLDQpICE9ICgyLDEpOyBhc3NpZ24oKDIsNCksIDIpLCBhc3NpZ24oKDIsMSksIDIpLg==",lower_bound)).
input_node(assign((1,1),2),false, (head_upper_bound, "e2Fzc2lnbigoMSwxKSwxKTsgYXNzaWduKCgxLDEpLDIpOyBhc3NpZ24oKDEsMSksMyk7IGFzc2lnbigoMSwxKSw0KX0gPSAxIDotIDEgPSAxLi40OyAxID0gMS4uNC4=")).
input_node(assign((1,2),2),true, (constraint, "Oi0gYmxvY2soKHN1YiwwLDApLCAoMiwyKSk7IDIgPSAxLi40OyBub3QgYXNzaWduKCgyLDIpLDIpOyBub3QgYXNzaWduKCgyLDEpLDIpOyBub3QgYXNzaWduKCgxLDIpLDIpOyBub3QgYXNzaWduKCgxLDEpLDIpLg==",lower_bound)).
30 changes: 23 additions & 7 deletions ucorexplain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from clingraph.clingo_utils import ClingraphContext # type: ignore
from clingraph.graphviz import compute_graphs, render # type: ignore
from clingraph.orm import Factbase # type: ignore
from clingraph.clingo_utils import add_svg_interaction, add_elements_ids

AnswerSetElement = Union[GroundAtom, tuple[GroundAtom, bool]]
AnswerSet = tuple[AnswerSetElement, ...]
Expand Down Expand Up @@ -59,25 +60,39 @@ def print_with_title(title, value):


def visualize(file_path) -> None:
fb = Factbase(prefix="viz_")
fb = Factbase()
ctl = Control([])
ctx = ClingraphContext()
add_elements_ids(ctl)
ctl.load(file_path)
ctl.load(os.path.join(ENCODINGS_PATH, "clingraph.lp"))
enable_python()

ctl.ground([("base", [])], context=ctx)
ctl.solve(on_model=fb.add_model)
graphs = compute_graphs(fb)
render(graphs, view=True)
paths = render(graphs, view=True, format="svg")
add_svg_interaction([paths])


def ruleto64(rule_str):
s = str(rule_str).strip('"')
r = SymbolicRule.parse(s)
r = r.with_chopped_body(
with_backward_search=True, backward_search_symbols=(";", " :-")
)
encoded = base64.b64encode(str(r).encode("ascii"))
return encoded


def save_graph(graph):
with open("graph.lp", "wb") as file_to_save:
for a in graph:
file_to_save.write(a.predicate_name.encode())
file_to_save.write(("input_" + a.predicate_name).encode())
file_to_save.write(
"({}".format(",".join([str(a) for a in a.arguments[:-1]])).encode()
"({}".format(
",".join([str(a).strip('"') for a in a.arguments[:-1]])
).encode()
)

if a.predicate_name == "node":
Expand All @@ -86,16 +101,17 @@ def save_graph(graph):
file_to_save.write(str(t[0]).encode())
if len(t) > 1:
file_to_save.write(', "'.encode())
file_to_save.write(base64.b64encode(str(t[1]).encode("ascii")))
s = ruleto64(str(t[1]))
file_to_save.write(s)
file_to_save.write('"'.encode())
if len(t) == 3:
file_to_save.write(",".encode())
file_to_save.write(str(t[2]).encode())
file_to_save.write(")".encode())
if a.predicate_name == "link":
t = a.arguments[-1]
s = ruleto64(str(a.arguments[-1]))
file_to_save.write(', "'.encode())
file_to_save.write(base64.b64encode(str(t).encode("ascii")))
file_to_save.write(s)
file_to_save.write('"'.encode())

file_to_save.write(").\n".encode())
3 changes: 3 additions & 0 deletions ucorexplain/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,15 @@ def main():
# Moving stuff would go here

# compute DAG
pus_program = []
graph = explanation_graph(
program=program,
answer_set=answer_set,
herbrand_base=herbrand_base,
query=query,
collect_pus_program=pus_program,
)
print_with_title("Grounded Program with selectors", pus_program)

print_with_title("Graph", graph)

Expand Down
62 changes: 41 additions & 21 deletions ucorexplain/encodings/clingraph.lp
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,48 @@ from clingo.symbol import String
import base64

def fromb64(s):
s = str(s).strip('"')
decoded = base64.b64decode(s).decode('utf-8')
pos = decoded.find("__pus")
decoded = decoded[1:pos]+"."
s = str(s)
decoded = base64.b64decode(s).decode('ascii')
return String(decoded)

#end.
viz_node(X):-node(X,_,_).
viz_attr(node,X, style, filled):-node(X,_,_).
viz_attr(node,X, shape, plain):-node(X,_,_).
viz_attr(node, X, fillcolor, @color(red,70)):-node(X,false,_).
viz_attr(node, X, fillcolor, @color(green,70)):-node(X,true,_).
viz_attr(node, X, label, @concat(
"<<TABLE cellborder='1' border='0' cellspacing='0'>",
node_rule(X,R):-input_node(X,_,(_,R,_)).
node_rule(X,R):-input_node(X,_,(_,R)).
node_rule(X,""):-input_node(X,_,(_)), not input_node(X,_,(_,_)), not input_node(X,_,(_,_,_)).
node_reason(X,@concat(R," (",R',")")):-input_node(X,_,(R,_,R')).
node_reason(X,R):-input_node(X,_,(R,_)).
node_reason(X,R):-input_node(X,_,(R)), not input_node(X,_,(_,_)), not input_node(X,_,(_,_,_)).

node(X):-input_node(X,_,_).
attr(node,X, style, filled):-input_node(X,_,_).
attr(node,X, shape, plain):-input_node(X,_,_).
attr(node, X, fillcolor, @color(red,70)):-input_node(X,false,_).
attr(node, X, fillcolor, @color(green,70)):-input_node(X,true,_).
attr(node, X, label, @concat(
"<<TABLE cellborder='1' border='{{border}}' cellspacing='0'>",
"<TR><TD><b>{{name}}</b></TD></TR>",
"<TR><TD><i>{{reason}}</i><br/>{{rule}}</TD></TR>",
"</TABLE>>")):-node(X,_,_).
viz_attr(node, X, (label,reason),@concat(R," (", R',")")):-node(X,_,(R,_,R')).
viz_attr(node, X, (label,reason), R):-node(X,_,(R,_)).
viz_attr(node, X, (label,reason), R):-node(X,_,(R)), not node(X,_,(_,_)), not node(X,_,(_,_,_)).
viz_attr(node, X, (label,rule),@fromb64(R)):-node(X,_,(_,R,_)).
viz_attr(node, X, (label,rule), @fromb64(R)):-node(X,_,(_,R)).
viz_attr(node, X, (label,rule), ""):- node(X,_,(_)), not node(X,_,(_,_)), not node(X,_,(_,_,_)).
viz_attr(node, X, (label,name), X):-node(X,_,_).
viz_edge((X,Y)):-link(X,Y,_).
"<TR><TD><i>{{reason}}</i><br/>",
"<FONT face='monospace'>{{rule}}</FONT></TD></TR>",
"</TABLE>>")):-input_node(X,_,_).
attr(node, X, (label,reason), R):-node_reason(X,R).
attr(node, X, (label,rule),@fromb64(R)):-node_rule(X,R).
attr(node, X, (label,name), X):-input_node(X,_,_).
attr(node, X, (label,border), 0):-input_node(X,_,_), input_link(X,Y,_), Y!=X.
attr(node, X, (label,border), 2):-input_node(X,_,_), #false: input_link(X,Y,_), Y!=X.
edge((X,Y)):-input_link(X,Y,_),X!=Y.
attr(edge,(X,Y),label,"<<FONT face='monospace'>{{rule}}</FONT>>"):-input_link(X,Y,R),X!=Y, not node_rule(X,R).
attr(edge,(X,Y),(label,rule), @fromb64(R)):-input_link(X,Y,R),X!=Y, not node_rule(X,R).


linked_element(node,Y,X):-input_link(X,Y,_).
linked_element(node,X,X):-input_node(X,_,_).
linked_element(edge,(X,Y),X):-input_link(X,Y,_),edge((X,Y)).

% SVG interaction
root(X):- input_node(X,_,_), #count{Y: input_node(Y,_,_), input_link(Y,X,_), Y!=X}=0.
attr(node,X,class,@svg_init("visibility","hidden")):-input_node(X,_,_), not root(X).
attr(edge,E,class,@svg_init("visibility","hidden")):-edge(E).

attr(Type,E,class,@svg("click",X,"visibility","visible")):-linked_element(Type,E,X).
attr(Type,E,class,@svg("mouseenter",X,"opacity","1")):-linked_element(Type,E,X).
attr(Type,E,class,@svg("mouseleave",X,"opacity","0.3")):-linked_element(Type,E,X).

0 comments on commit 1d86438

Please sign in to comment.