def test_undefined_warning(): assert not clyngor.have_clingo_module() with pytest.raises(clyngor.ASPWarning) as excinfo: tuple(clyngor.solve((), inline='b:- c.', error_on_warning=True, force_tempfile=True)) assert excinfo.value.atom == 'c' assert len(excinfo.value.args) == 1 start = "atom 'c' does not occur in any rule head in file /tmp/tmp" assert excinfo.value.args[0].startswith(start) assert excinfo.value.args[0].endswith(" at line 1 and column 5-6") # NB: the following should NOT raise any error (default value) tuple(clyngor.solve((), inline='b:- c.', error_on_warning=False)) tuple(clyngor.solve((), inline='b:- c.'))
def draw_context(atoms: iter): """Draw given context is stdout""" # print('JJONNY:', type(atoms)) # print('AMONDS:', atoms) if isinstance(atoms, str): atoms = next(clyngor.solve([], inline=atoms).int_not_parsed) # print('JJONNY:', type(atoms)) # print('AMONDS:', tuple(atoms)) objs, atts = set(), set() have = defaultdict(set) for _, (obj, att) in atoms: objs.add(obj) atts.add(att) have[obj].add(att) objs = sorted(objs) atts = sorted(atts) obj_max_width = max(len(obj) for obj in objs) att_max_width = max(len(att) for att in atts) print(' ' * obj_max_width, '|', ' | '.join(att.center(att_max_width) for att in atts)) for obj in objs: print( obj.rjust(obj_max_width), '|', ' | '.join( ('X' if att in have[obj] else ' ').center(att_max_width) for att in atts))
def test_bug_issue_7(): "inconsistencies in parsing when clingo module is used" models = clyngor.solve(inline='a(1). e(X):- a(X).', use_clingo_module=True).sorted.atoms_as_string model = next(models) assert model == ('a(1)', 'e(1)') with pytest.raises(StopIteration): next(models) # only one model
def links_from_dirty_lines(lines:str, edge_predicate:str=edge_predicate): """Use the bulldozer to handle these lines by calling ASP solver""" models = clyngor.solve(inline=''.join(map(str,lines))).careful_parsing for model in models.by_predicate: for args in model.get(edge_predicate, ()): if len(args) == 2: yield args
def extract_transformation_known_reactions(input_file, output_folder): print('~~~~~Extraction of Reaction~~~~~') reaction_extraction_script = os.path.join( *[root, 'asp', 'CompareMolecules.lp']) reaction_solver = clyngor.solve([input_file, reaction_extraction_script], use_clingo_module=False) known_transformations_path = os.path.join(output_folder, 'known_transformations.tsv') with open(known_transformations_path, 'w') as output_file: csvwriter = csv.writer(output_file, delimiter='\t') csvwriter.writerow([ 'reaction_name', 'molecule_A', 'molecule_B', 'bond_type', 'atom_1', 'atom_2' ]) for atom in next(reaction_solver.parse_args.int_not_parsed.sorted): if 'diff' in atom[0]: reaction_id = atom[1][0] molecule_A_name = atom[1][1] molecule_B_name = atom[1][2] bond_type = atom[1][3] atom_1 = atom[1][4] atom_2 = atom[1][5] csvwriter.writerow([ reaction_id, molecule_A_name, molecule_B_name, bond_type, atom_1, atom_2 ])
def biseau_encoding_of_interactions(compress_to_bubble:bool=False): "Return ASP that encodes the interaction graph for biseau" asp_code = """ link(C,D) :- share(C,D,_). dot_property(C,D,penwidth,N) :- share(C,D,N). obj_property(graph,bgcolor,black). obj_property(edge,(fontcolor;color),white). obj_property(node,(fontcolor;color),white). obj_property(edge,arrowhead,none). label(C,D,N) :- share(C,D,N) ; N>1. """ def gen_data(): for (one, two), nb_interaction in get_characters_interactions().items(): yield f'share("{one}","{two}",{nb_interaction}).' asp = asp_code + ' '.join(gen_data()) if compress_to_bubble: # generate bubble file import clyngor, powergrasp with open(FILE_OUT_ASP, 'w') as fd: for model in clyngor.solve(inline=asp).by_predicate: for a, b in model.get('link', ()): fd.write(f'edge({a},{b}).\n') with open(FILE_OUT_BBL, 'w') as fd: for line in powergrasp.compress_by_cc(FILE_OUT_ASP): fd.write(line.replace('_c32_', '_').replace('_c39_', "'") + '\n') return asp
def read_lp(lines: iter): """Yield, in that order: - number of objects - number of attributes - tuple of objects - tuple of attributes - for each object: - (object, bools) """ lines = '\n'.join(lines) objects, attributes, relations = set(), set(), {} for answer in clyngor.solve( inline=lines).by_arity.careful_parsing.int_not_parsed: for obj, att in answer.get('rel/2', ()): obj = obj[1:-1] if obj[0] == obj[-1] == '"' else obj att = att[1:-1] if att[0] == att[-1] == '"' else att objects.add(obj) attributes.add(att) relations.setdefault(obj, set()).add(att) objects = tuple(sorted(tuple(objects))) attributes = tuple(sorted(tuple(attributes))) yield len(objects) yield len(attributes) yield tuple(objects) yield tuple(attributes) for object in objects: hold = relations[object] yield object, tuple(attr in hold for attr in attributes)
def test_constants(asp_code_with_constants): answers = tuple(solve([], inline=asp_code_with_constants, constants={'a': 2}, print_command=True).by_predicate) assert len(answers) == 1 answer = answers[0]['q'] assert len(answer) == 1 assert next(iter(answer)) == (2,)
def object_intersections_ASP(context, invcontext, asp_data: str): "Yield formal concepts of the context using OI algorithm implemented in ASP" G = set(context.keys()) M = set(invcontext.keys()) C = [(derived_objects(invcontext, M), M)] # list of all found formal concepts for obj in G: for ext, int in C: data = (f'\nobject({obj}).\n' + ' '.join(f'concept_ext({x}).' for x in ext) + '\n' + ' '.join(f'concept_int({x}).' for x in int) + '\n' + ' '.join(f'concepts_int({idx},{x}).' for x in int for idx, (_, int) in enumerate(C))) models = clyngor.solve('algo-oi.lp', inline=asp_data + data).by_arity model = next(models, None) if model is None: continue # no concept yielded extent, intent = set(), set() for obj, in model.get('ext/1', ()): extent.add(obj) for att, in model.get('int/1', ()): intent.add(att) print(extent, intent) C.append((frozenset(extent), frozenset(intent))) return C
def test_syntax_error_semicolon(): with pytest.raises(clyngor.ASPSyntaxError) as excinfo: tuple(clyngor.solve((), inline='color(X,red):- ;int(X,"adult").', force_tempfile=True)) assert excinfo.value.filename.startswith('/tmp/tmp') assert excinfo.value.lineno == 1 assert excinfo.value.offset == 16 assert excinfo.value.msg.startswith('unexpected ; in file /tmp/tmp') assert excinfo.value.msg.endswith(' at line 1 and column 16-17')
def ASP(source_code: str): """Return the answer sets obtained by running the solver on given raw source code. source_code -- ASP source code """ return solve(files=(), inline=source_code)
def test_local_propagator_hidden_by_clingo(): """Prove that main function (and therefore locally defined propagators) is ignored from code if called with clingo module """ clingo_models = set(clyngor.solve(inline=PYCONSTRAINT_CODE, use_clingo_module=True)) clyngor_models = set(clyngor.solve(inline=PYCONSTRAINT_CODE, use_clingo_module=False)) assert len(clingo_models) == 3 assert len(clyngor_models) == 2 assert clingo_models == { frozenset({('b', (1,))}), frozenset({('b', (2,))}), frozenset({('b', (3,))}), } assert clyngor_models == { frozenset({('b', (1,))}), frozenset({('b', (3,))}), }
def solve(input_data: str, asp_routine: str) -> dict: if os.path.exists(input_data): files = asp_routine, input_data inline = None else: files = asp_routine, inline = input_data return clyngor.solve(files, inline=input_data).by_predicate
def test_syntax_error_brace(): with pytest.raises(clyngor.ASPSyntaxError) as excinfo: tuple(clyngor.solve((), inline='color(X,red):- {{}}.', force_tempfile=True)) assert excinfo.value.filename.startswith('/tmp/tmp') assert excinfo.value.lineno == 1 assert excinfo.value.offset == 17 assert excinfo.value.msg.startswith('unexpected { in file /tmp/tmp') assert excinfo.value.msg.endswith(' at line 1 and column 17-18')
def test_syntax_error_brace_with_stdin(): with pytest.raises(clyngor.ASPSyntaxError) as excinfo: tuple(clyngor.solve((), inline='color(X,red):- {{}}.')) assert excinfo.value.filename == '-' assert excinfo.value.lineno == 1 assert excinfo.value.offset == 17 assert excinfo.value.msg.startswith('unexpected { in file -') assert excinfo.value.msg.endswith(' at line 1 and column 17-18')
def test_with_opts(): ASP = r""" 1 { a; b }. #minimize { 2,t:a; 2,t:b; 1,u:b; 2,v:b }. """ answer = solve(inline=ASP, options='--opt-mode=optN') found = list(utils.opt_models_from_clyngor_answers(answer)) assert found == [frozenset({('a', ())})]
def test_restricted_and_literal_outputs(): asp_code = 'a. link(a). #show link/1. #show 3. #show "hello !".' answers = tuple(solve([], inline=asp_code).by_predicate) assert len(answers) == 1 answer = answers[0] print(answers) assert len(answer) == 3 assert set(answer) == {'link', 3, '"hello !"'} assert answer == {'link': {('a',)}, 3: {()}, '"hello !"': {()}}
def test_literal_outputs_by_show_working(): answers = tuple(solve(inline=LITERALS_ARE_SHOWN).by_predicate) print(answers) assert len(answers) == 1 answer = answers[0] print(answers) assert len(answer) == 3 assert set(answer) == {'link', '"hello !"', 3} assert answer == {'link': {('a', )}, '"hello !"': {()}, 3: {()}}
def test_no_time_limit_queens(): """Queens yield at least one solution when enough time is provided. This is tested in order to prove that the time limit option works properly in the `test_time_limit_no_solutions` function. """ answers = solve([], inline=QUEENS, nb_model=1) assert sum(1 for answer in answers) == 1
def ASP(source_code: str, **kwargs): """Return the answer sets obtained by running the solver on given raw source code. source_code -- ASP source code kwargs -- keyword arguments to be given to solve() call """ return solve(inline=source_code, stats=False, **kwargs)
def test_basic_decorator_usage(): models = tuple(clyngor.solve(inline=ASP_SOURCE).by_predicate) assert len(models) == 1 model = models[0] assert model == { 'p': frozenset({('"hellohello"', ), (6, ), (5, )}), 'q': frozenset({('"aa"', 2)}), 'r': frozenset({('"abababa"', )}), }
def test_many_call_to_test_file_closing(): """at some point, if files are not closed, this should fail""" for idx in range(100): # arbitrary number of call leading to an error models = solve(inline=f'a({idx}).', delete_tempfile=True, force_tempfile=True) # force the use of tempfile assert next(models) == {('a', (idx, ))} with pytest.raises(StopIteration): next(models)
def get_solver(filename): answers = solve(filename) # Returns the solution in the form of Frozenset objects for answer in answers: ls = answer for x in ls: for y in x: if(y!='x'): solution_list.append(y) return(solution_list)
def concepts_in(context: str): """Return the concepts found in given context built by rel/2 atoms""" models = clyngor.solve('enumerate_concepts.lp', inline=context).by_predicate for model in models: extent = frozenset(args[0] for args in model.get('obj', ()) if len(args) == 1) intent = frozenset(args[0] for args in model.get('att', ()) if len(args) == 1) yield extent, intent
def test_pyconstraint_from_embedded_code(): possible_values = {1, 2, 3} for value_to_avoid in possible_values: source = PYCONSTRAINT_CODE_ARGUMENT.format(value_to_avoid=value_to_avoid) models = set(clyngor.solve(inline=source, use_clingo_module=False, error_on_warning=True)) assert len(models) == len(possible_values) - 1 assert models == { frozenset({('b', (val,))}) for val in possible_values if val != value_to_avoid }
def decode(*args, decoders: iter, **kwargs): """Yield objects built from decoders from all models. Expects same (kw)args as clyngor.solve, but decoders MUST be provided. """ decoders = tuple(decoders) for model in solve(*args, **kwargs).by_predicate: for decoder in decoders: yield from objects_from_model(decoder, model)
def _build_solver(step:int, lowerbound:int, upperbound:int, files:iter, graph:str, options:str) -> iter: """Return iterator over found models""" constants = {'k': step, 'lowerbound': lowerbound, 'upperbound': upperbound} if COVERED_EDGES_FROM_ASP: constants['covered_edges_from_asp'] = 1 options += CLINGO_MULTITHREADING models = clyngor.solve(files=tuple(files), inline=str(graph), constants=constants, stats=False, options=options) if SHOW_STORY: print('SOLVE', models.command) return models.by_predicate.careful_parsing
def ASP_one_model(source_code: str, **kwargs): """Return the first answer set obtained by running the solver on given raw source code. source_code -- ASP source code kwargs -- keyword arguments to be given to solve() call """ models = solve(inline=source_code, stats=False, nb_model=1, **kwargs) return next(models, None)
def maybe_valid_grid(grid, rules_fn): rules_fn = rules_fn.decode('utf-8') # bytes to string facts = '\n'.join(map(factify_cellHasDigit, grid.items())) answers = solve(rules_fn, inline=facts, nb_model=100, stats=True) nmsf = 0 for nmsf, model in enumerate(answers, start=1): pass nms = answers.statistics.get('Models', None) if nms is None: return ('error', 'No solutions found.') else: return ('ok', f'{nms} solutions found.')
def test_syntax_error(): assert not clyngor.have_clingo_module() with pytest.raises(clyngor.ASPSyntaxError) as excinfo: tuple(clyngor.solve((), inline='invalid', force_tempfile=True)) assert excinfo.value.filename.startswith('/tmp/tmp') assert excinfo.value.lineno == 2 assert excinfo.value.offset == 1 assert excinfo.value.payload['char_end'] == 2 assert excinfo.value.msg.startswith('unexpected EOF in file /tmp/tmp') assert excinfo.value.msg.endswith(' at line 2 and column 1-2')
def test_pyconstraint_recursion_problem(): """Show that the python constraint handles recursive propagations and is able to discard models appropriatly. if the solving hangs, then probably the constraint implementation is blocked by an infinite loop of propagations during discarding. if the solving yields inapropriate models, it's (among other) because the clauses added by the constraint object are kept (which is forced by design by clingo's API). Current state : propagation loop is prevented by a state mecanism. However, the inapropriate model solving is due to many problems, one being clingo's API itself. Some ressources for future solving of that feature-killer issue: - what we want is not possible. By design. https://sourceforge.net/p/potassco/mailman/message/36358095/ - some other peoples wants it, the solution seems to be external atoms https://sourceforge.net/p/potassco/mailman/message/35480361/ - but external atoms are not handlable during solving through propagator API https://potassco.org/clingo/python-api/current/clingo.html#PropagateControl - cool find with propagators: https://twitter.com/rndmcnlly/status/867605489789489152 """ source = textwrap.dedent(""" #script(python) from clyngor import Constraint, Variable as V, Main def formula(inputs): return inputs['p', (2,)] constraint = Constraint(formula, {('p', (V,))}) main = Main(propagators=constraint) #end. {p(1..3)}. % powerset of p(X). """) models = set( clyngor.solve(inline=source, use_clingo_module=False, error_on_warning=True)) assert models == { frozenset(()), frozenset({('p', (1, ))}), frozenset({('p', (2, ))}), frozenset({('p', (3, ))}), }, "this may fail because a bug was fixed" return # the models that are really to be expected: # (and given by a really working implementation) assert models == { frozenset(()), frozenset({('p', (1, ))}), frozenset({('p', (3, ))}), frozenset({('p', (1, )), ('p', (3, ))}), }
def extract_context(input_file:str, names:[str]=('edge', 'rel'), symetric:bool=False, anonymize:bool=False, keep_quotes:bool=False, prefixed:bool=False) -> Context: model = next(clyngor.solve(input_file).careful_parsing.by_predicate) relations = model.get('edge', model.get('rel')) if not relations: raise ValueError("Given file ({}) do not contains edge/2 or rel/2, but {}" "".format(input_file, ', '.join(links))) assert all(len(t) == 2 for t in relations) # format the identifiers formatted = lambda s: s.strip('"') if keep_quotes: formatted = lambda s: s.strip('"') if anonymize: gen_ids = itertools.count(1) ids = defaultdict(lambda: next(gen_ids)) formatted = lambda s: str(ids[s]) relations = ( (formatted(obj), formatted(att)) for obj, att in relations ) with_prefix = lambda o, a: (o, a) if prefixed: with_prefix = lambda o, a: ('o' + o, 'a' + a) if symetric: relations = frozenset( with_prefix(ext, int_) for obj, att in relations for ext, int_ in ((obj, att), (att, obj)) ) else: # keep given order relations = frozenset( with_prefix(obj, att) for obj, att in relations ) objects = tuple(frozenset(obj for obj, _ in relations)) attributes = tuple(frozenset(att for _, att in relations)) return Context(objects, attributes, relations)