Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AnswerSetQuery: API feature to query answer sets in a fluent way #287

Merged
merged 6 commits into from
Aug 9, 2021

Conversation

madmike200590
Copy link
Collaborator

This PR adds a new class AnswerSetQuery that allows API users to process answer sets with a bit less boilerplate code.

Usage

Answer set queries can be used via the new AnswerSet#query method that accepts an AnswerSetQuery as its argument.
For an intuition on how to use answer set queries, see below examples:

Answer Set {
    p(a),
    p("a"),
    p(b)
    p(1),
    p(2),
    p(3),
    p(4),
    p(5),
    q(a),
    q(b),
    r(x, f(x)),
    r(x, f(y)),
    r(y, f(x)),
    r(x, y)
}

Some queries:
List<Atom> queryResult = answerSet.query(AnswerSetQuery.forPredicate(Predicate.getInstance("p", 1)));
// queryResult contains all instances of p/1

List<Atom> queryResult = answerSet.query(
    AnswerSetQuery.forPredicate(Predicate.getInstance("p", 1))
	.withConstantEquals(0, "a");
// queryResult contains p(a), but not p("a") which is a string rather than a symbolic constant.

List<Atom> queryResult = answerSet.query(
    AnswerSetQuery.forPredicate(Predicate.getInstance("p", 1))
        .withStringEquals(0, "a");
// queryResult contains p("a"), but not p(a)

java.util.function.Predicate<Term> isInteger = (term) -> {
	if (!(term instanceof ConstantTerm<?>)) {
		return false;
	}
	String strValue = ((ConstantTerm<?>) term).getObject().toString();
	return strValue.matches("[0-9]+");
};
AnswerSetQuery evenIntegers = 
    AnswerSetQuery.forPredicate(Predicate.getInstance("p", 1))
       .withFilter(0, isInteger.and((term) -> (Integer.valueOf(((ConstantTerm<?>) term).getObject().toString()) % 2 == 0)));
List<Atom> queryResult = answerSet.query(evenIntegers);
// queryResult = [p(2), p(4)]

AnswerSetQuery query = 
    AnswerSetQuery.forPredicate(Predicate.getInstance("r", 2))
        .withConstantEquals(0, "x")
        .withFunctionTerm(1, "f", 1);
List<Atom> queryResult = answerSet.query(query);
// queryResult = [r(x, f(x)), r(x, f(y))]

@AntoniusW
Copy link
Collaborator

I have a few general questions first:

  1. Can we match multiple predicates with one query, or do we need to run multiple queries and then build the union of the query results to get "match p and q predicates"?
  2. It feels like a simple query-expression language is almost there already. Have you thought about adding something that takes kind of a regex and constructs an appropriate AnswerSetQuery?

@madmike200590
Copy link
Collaborator Author

  1. Can we match multiple predicates with one query, or do we need to run multiple queries and then build the union of the query results to get "match p and q predicates"?

Currently the idea is to only match single predicates per query. I thought about doing more than one and then have what you suggest, but then AnswerSet#query would have to return either a Map<Predicate, List<Atom>> or a new (filtered) AnswerSet, which would require an additional sorting step for each matched predicate (since predicate instances are SortedSets). While both possibilities definitely make sense, I decided to keep it simple for now.

  1. It feels like a simple query-expression language is almost there already. Have you thought about adding something that takes kind of a regex and constructs an appropriate AnswerSetQuery?

Do you mean just adding an additional filter method such as withStringTermMatching(int termIdx, String regex) or a more general "pattern matching" such as AnswerSetQuery.fromExpression("p[0-9]?\([0-9]+\, f([a-z]))")? The first is easy to accomplish, the second variant would be undoubtedly useful, but still a bit of effort. Again, I'd suggest to keep it simple for now, additional convenience methods and further features can be added when we have the basic version in use for a bit and get a better feeling for what's missing.

Copy link
Collaborator

@AntoniusW AntoniusW left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, aside from some minor suggestions.

Comment on lines +63 to +65
* @param termIdx
* @param str
* @return
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A general thought on this: our IDEs create these javadoc parameter descriptions automatically, but as long as we do not fill them in, we might as well delete the javadoc parameters.

* @return
*/
public AnswerSetQuery withConstantEquals(int termIdx, String str) {
return this.withFilter(termIdx, AnswerSetQuery.constantTermEquals(str));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method constantTermEquals is only used here and can be inlined as follows:

Suggested change
return this.withFilter(termIdx, AnswerSetQuery.constantTermEquals(str));
return this.withFilter(termIdx, (t) -> AnswerSetQuery.constantTermEquals(t, str));

Comment on lines +172 to +177
private static java.util.function.Predicate<Term> constantTermEquals(final String str) {
java.util.function.Predicate<Term> equalsGivenString = (t) -> {
return AnswerSetQuery.constantTermEquals(t, str);
};
return equalsGivenString;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method can be deleted if the above suggestion to inline it is accepted.

madmike200590 and others added 4 commits July 29, 2021 17:43
Co-authored-by: Antonius Weinzierl <AntoniusW@users.noreply.github.com>
Co-authored-by: Antonius Weinzierl <AntoniusW@users.noreply.github.com>
@madmike200590 madmike200590 merged commit e8feb4e into master Aug 9, 2021
@madmike200590 madmike200590 deleted the atom_queries branch August 9, 2021 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants