def program_to_endpoints(program: str or tuple, node_as_index: bool = True) -> dict: """Return the atoms endpoints computed from given parsed ASP program. program -- either a source code as string or a parsed one node_as_index -- return nodes as index of rules in the source code instead of rules themselves """ if isinstance(program, str): program = tuple(parse_asp_program(program, do=CodeAsTuple())) atom_source = defaultdict(set) # predicate -> rules yielding it atom_target = defaultdict(set) # predicate -> rules using it # explore the full structure to populate sources and targets for idx, (type, *data) in enumerate(program): if type == 'rule': head, body = data atom_source[head[1]].add(idx) for (subtype, *subdata) in body: if subtype in {'term', '¬term'}: atom_target[subdata[0]].add(idx) elif subtype in {'forall', '¬forall'}: atom_target[subdata[0]].add(idx) for (subsubtype, *subsubdata) in subdata[2]: if subsubtype == 'term': atom_target[subsubdata[0]].add(idx) else: assert False, "Type {} is unexpected in forall body".format( subtype) else: assert False, "Type {} is unexpected in rule body".format( subtype) elif type == 'term': atom_source[data[0]].add(idx) elif type == 'selection': for (subtype, *subdata) in data[2]: if subtype in {'term', '¬term', 'forall', '¬forall'}: atom_source[subdata[0]].add(idx) else: assert False, "Type {} is unexpected in selection".format( subtype) elif type == 'constraint': for (subtype, *subdata) in data[0]: if subtype in {'term', '¬term', 'forall', '¬forall'}: atom_target[subdata[0]].add(idx) else: assert False, "Type {} is unexpected in selection".format( subtype) else: assert False, "Type {} is unexpected at first level".format(type) if node_as_index: return dict(atom_source), dict(atom_target) else: # use the parsed rules themselves return tuple({ program[pred]: frozenset(program[succ] for succ in succs) for pred, succs in graph.items() } for graph in (atom_source, atom_target))
def test_disjunction(): ASP_CODE = r""" rel(a,(c;d)). rel(b,(d;e)). rel(c,(e(1),f;g,h(2))). """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 3 first, second, third = rules print('FIRST:', first) expected = ('term', 'rel', (('term', 'a', ()), ('disjunction', (('term', 'c', ()), ), (('term', 'd', ()), )))) print('EXPEC:', expected) assert first == expected print('SECOD:', second) expected = ('term', 'rel', (('term', 'b', ()), ('disjunction', (('term', 'd', ()), ), (('term', 'e', ()), )))) print('EXPEC:', expected) assert second == expected print('THIRD:', third) expected = ('term', 'rel', (('term', 'c', ()), ('disjunction', (('term', 'e', (1, )), ('term', 'f', ())), (('term', 'g', ()), ('term', 'h', (2, )))))) print('EXPEC:', expected) assert third == expected
def lines_for(rule:tuple or str, id:int or str=1) -> tuple: """Return the parsed construction of debug lines debugging given rule""" if isinstance(rule, str): rule = tuple(precise_parser.parse_asp_program(rule))[0] print('RULE:', rule) head = rule[1] body = rule[2] assert len(body) > 0, "empty body" assert rule[0] == 'rule', "input data must a rule" assert len(rule[1]) == 3 assert head[0] == 'term', "head must be a term" ruleid = str(id) print('ID:', ruleid) head = ('term', 'head', (ruleid,)) conditions = tuple(term for term in body if not term[0].startswith('¬')) constraints = tuple(term for term in body if term[0].startswith('¬')) print('CONDITIONS:', conditions) print('CONSTRAINTS:', constraints) not_conditions = tuple(('¬' + type, *data) for type, *data in conditions) not_constraints = tuple(('not', constraint) for constraint in constraints) ok = (('term', 'ok', (ruleid,)),) return ( ok[0], ('rule', ('term', 'head', (ruleid,)), (('term', 'ap', (ruleid,)), ('¬term', 'ko', (ruleid,)))), ('rule', ('term', 'ap', (ruleid,)), ok + conditions + constraints), ('rule', ('term', 'bl', (ruleid,)), ok + not_conditions), ('rule', ('term', 'bl', (ruleid,)), ok + not_constraints), )
def test_forall(): ASP_CODE = r""" a:- rel(X,Y): obj(X), att(Y). b:- not rel(X,Y): obj(X), att(Y). c:- not rel(X,Y): obj(X), att(Y) ; rel(c,_). """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 3 first, second, third = rules print('FIRST:', first) expected = ('rule', ('term', 'a', ()), (('forall', 'rel', ('X', 'Y'), (('term', 'obj', ('X', )), ('term', 'att', ('Y', )))), )) print('EXPEC:', expected) assert first == expected print('SECOD:', second) expected = ('rule', ('term', 'b', ()), (('¬forall', 'rel', ('X', 'Y'), (('term', 'obj', ('X', )), ('term', 'att', ('Y', )))), )) print('EXPEC:', expected) assert second == expected print('THIRD:', third) expected = ('rule', ('term', 'c', ()), (('¬forall', 'rel', ('X', 'Y'), (('term', 'obj', ('X', )), ('term', 'att', ('Y', )))), ('term', 'rel', (('term', 'c', ()), '_')))) print('EXPEC:', expected) assert third == expected
def test_rules(): ASP_CODE = r""" a. b("les amis, \"coucou\"."). obj(X):- rel(X,_) ; rel(X,Y): att(Y). att(Y):- rel(_,Y) ; rel(X,Y): obj(X). """ rules = tuple(parse_asp_program(ASP_CODE)) assert len(rules) == 4 first, second, third, fourth = rules assert first == ('term', 'a', ()) print('SECOND:', second) assert second == ('term', 'b', (('text', r'les amis, \"coucou\".'), )) print('THIRD:', third) expected = ('rule', ('term', 'obj', ('X', )), ( ('term', 'rel', ('X', '_')), ('forall', 'rel', ('X', 'Y'), (('term', 'att', ('Y', )), )), )) print('EXPEC:', expected) assert third == expected print('FOURTH:', fourth) expected = ('rule', ('term', 'att', ('Y', )), ( ('term', 'rel', ('_', 'Y')), ('forall', 'rel', ('X', 'Y'), (('term', 'obj', ('X', )), )), )) print('EXPECT:', expected) assert fourth == expected
def test_const_text_with_inlined_comment(): ASP_CODE = r""" #const ident="%*text\" *%". """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 1 assert rules[0] == ('const', 'ident', ('text', '')), ( "if this fail, it's because comments are correctly handled.")
def program_to_dependancy_graph(program: str or tuple, node_as_index: bool = True, have_comments: bool = True) -> dict: """Most high level function: compute dependancy graph from the source code directly""" if isinstance(program, str): program = tuple( parse_asp_program(program, do=CodeAsTuple(), have_comments=have_comments)) endpoints = program_to_endpoints(program, node_as_index) return atoms_endpoints_to_dependancy_graph(*endpoints)
def test_const(): ASP_CODE = r""" %follows a show #const a=2. #const ident="". #const ident="text$%\"". """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 3 assert rules[0] == ('const', 'a', 2) assert rules[1] == ('const', 'ident', ('text', '')) assert rules[2] == ('const', 'ident', ('text', 'text$%\\"'))
def test_show(): ASP_CODE = r""" %follows a show #show a. #show a(X): b(X). #show a/1. """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 3 assert rules[0] == ('show', 'a', ()) assert rules[1] == ('show', 'a', ('X', ), (('term', 'b', ('X', )), )) assert rules[2] == ('show/n', 'a', 1)
def test_comments(): ASP_CODE = r""" %a. %. %{} %a:- test % *% % * ok. """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 1 assert rules[0] == ('term', 'ok', ())
def test_non_working_multiline_comments(): ASP_CODE = r""" % *% %* ai. b: %bug :c- *% % * ok. """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 1 assert rules[0] == ('term', 'ok', ()), "Multiline comments are not handled !"
def test_selection(): ASP_CODE = r""" 1 { sel(X): obj(X) } 1. { con(X,Y): obj(X), att(Y, 2) }. 2 { sel(X): obj(X) } 4:- anatom. """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 3 first, second, third = rules print('FIRST:', first) expected = ( 'selection', 1, 1, (('forall', 'sel', ('X', ), (('term', 'obj', ('X', )), )), ), ) print('EXPEC:', expected) assert first == expected print('SECOD:', second) expected = ( 'selection', 0, None, (( 'forall', 'con', ('X', 'Y'), ( ('term', 'obj', ('X', )), ('term', 'att', ('Y', 2)), ), ), ), ) print('EXPEC:', expected) assert second == expected print('THIRD:', third) expected = ('rule', ('selection', 2, 4, (( 'forall', 'sel', ('X', ), (('term', 'obj', ('X', )), ), ), )), (('term', 'anatom', ()), )) print('EXPEC:', expected) assert third == expected
def test_multirules(): ASP_CODE = r""" a;b:-c. b("string") ; a(X):- c(X). """ rules = tuple(parse_asp_program(ASP_CODE)) assert len(rules) == 2 assert rules[0] == ('multirule', ( ('term', 'a', ()), ('term', 'b', ()), ), (('term', 'c', ()), )) assert rules[1] == ('multirule', ( ('term', 'b', (('text', 'string'), )), ('term', 'a', ('X', )), ), (('term', 'c', ('X', )), ))
def test_constraint(): ASP_CODE = r""" :- a. :- not obj(X):obj(X). """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 2 first, second = rules print('FIRST:', first) expected = ('constraint', (('term', 'a', ()), )) print('EXPEC:', expected) assert first == expected print('SECOD:', second) expected = ('constraint', (('¬forall', 'obj', ('X', ), (('term', 'obj', ('X', )), )), )) print('EXPEC:', expected) assert second == expected
def test_term(): ASP_CODE = r""" a. b(1). c(2):- not b(2). """ rules = tuple(parse_asp_program(ASP_CODE, do=CodeAsTuple())) assert len(rules) == 3 first, second, third = rules print('FIRST:', first) expected = ('term', 'a', ()) print('EXPEC:', expected) assert first == expected print('SECOD:', second) expected = ('term', 'b', (1, )) print('EXPEC:', expected) assert second == expected print('THIRD:', third) expected = ('rule', ('term', 'c', (2, )), (('¬term', 'b', (2, )), )) print('EXPEC:', expected) assert third == expected