diff --git a/src/main/java/org/dice_research/cel/PruneCEL.java b/src/main/java/org/dice_research/cel/PruneCEL.java index f3bba41..1fe2f11 100644 --- a/src/main/java/org/dice_research/cel/PruneCEL.java +++ b/src/main/java/org/dice_research/cel/PruneCEL.java @@ -29,8 +29,8 @@ import org.dice_research.cel.refine.suggest.ExtendedSuggestor; import org.dice_research.cel.refine.suggest.SelectionScores; import org.dice_research.cel.refine.suggest.sparql.SparqlBasedSuggestor; +import org.dice_research.cel.score.AccuracyCalculator; import org.dice_research.cel.score.AvoidingPickySolutionsDecorator; -import org.dice_research.cel.score.BalancedAccuracyCalculator; import org.dice_research.cel.score.LengthBasedRefinementScorer; import org.dice_research.cel.score.ScoreCalculator; import org.dice_research.cel.score.ScoreCalculatorFactory; @@ -82,7 +82,7 @@ public List findClassExpression(Collection positi if (iResultPrinter != null) { iResultPrinter.setStartTime(startTime); } - long timeToStop = maxTime > 0 ? startTime + maxTime : 0; + long timeToStop = maxTime > 0 ? startTime + maxTime : 0; return findClassExpression(positive, negative, logStream, iResultPrinter, startTime, timeToStop); } @@ -235,14 +235,17 @@ public static void main(String[] args) throws Exception { // String endpoint = "http://localhost:9080/sparql"; // String endpoint = "http://localhost:3030/exp-bench/sparql"; // String endpoint = "http://localhost:3030/family/sparql"; - String endpoint = "http://dice-quan.cs.uni-paderborn.de:9050/sparql"; +// String endpoint = "http://dice-quan.cs.uni-paderborn.de:9050/sparql"; + // QALD9-plus-wikidata + String endpoint = "http://dice-quan.cs.uni-paderborn.de:9070/sparql"; // XXX Set description logic DescriptionLogic logic = DescriptionLogic.parse("ALC"); ScoreCalculatorFactory factory = null; // XXX Choose either F1 or balanced accuracy // factory = new F1MeasureCalculator.Factory(); - factory = new BalancedAccuracyCalculator.Factory(); + //factory = new BalancedAccuracyCalculator.Factory(); + factory = new AccuracyCalculator.Factory(); // Punish long expressions factory = new LengthBasedRefinementScorer.Factory(factory); @@ -267,7 +270,7 @@ public static void main(String[] args) throws Exception { // XXX Max iterations of the refinement // cel.setMaxIterations(1000); // XXX Maximum time (in ms) - cel.setMaxTime(60000); + cel.setMaxTime(600000); // XXX (Optional) try to avoid refining expressions that have not been created // in a promising way (i.e., just added a class to an existing expression // without changing the accuracy of the expression) @@ -279,8 +282,10 @@ public static void main(String[] args) throws Exception { // XXX Choose the learning problem (as JSON file) JSONLearningProblemReader reader = new JSONLearningProblemReader(); // Collection problems = reader.readProblems("LPs/Family/lps.json"); - //Collection problems = reader.readProblems("/home/micha/Downloads/TandF_MST5_reverse.json"); - Collection problems = reader.readProblems("/home/micha/Downloads/TandF_MST5.json"); +// Collection problems = reader.readProblems("/home/micha/Downloads/TandF_MST5_reverse.json"); + //Collection problems = reader.readProblems("/home/micha/Downloads/TandF_MST5.json"); + Collection problems = reader.readProblems("/home/micha/Downloads/TandF_deeppavlov_reverse.json"); + //Collection problems = reader.readProblems("/home/micha/Downloads/TandF_ganswer_reverse.json"); // Collection problems = // reader.readProblems("LPs/QA/TandF_MST5_reverse.json"); @@ -289,9 +294,15 @@ public static void main(String[] args) throws Exception { // ClassExpression ce = new SimpleQuantifiedRole(false, "http://w3id.org/dice-research/qa-bench#hasNlpParseTreeRoot", false, // new Junction(false, Suggestor.CONTEXT_POSITION_MARKER, new SimpleQuantifiedRole(false, "https://nlp.stanford.edu/nlp#obj", false, // NamedClass.BOTTOM))); -// ce = new Junction(true, -//// new SimpleQuantifiedRole(false, "http://w3id.org/dice-research/qa-bench#hasLiteralAnswer", false, -//// NamedClass.BOTTOM), +// ce = new Junction(false, +// new SimpleQuantifiedRole(false, "http://w3id.org/dice-research/qa-bench#hasQuestionWord", false, +// NamedClass.BOTTOM), +// new Junction(true, +// new SimpleQuantifiedRole(false, "http://w3id.org/dice-research/qa-bench#hasLiteralAnswer", false, +// NamedClass.BOTTOM), +// new SimpleQuantifiedRole(false, "http://w3id.org/dice-research/qa-bench#hasIRIAnswer", false, +// NamedClass.BOTTOM) +// ),Suggestor.CONTEXT_POSITION_MARKER); // new SimpleQuantifiedRole(true, "http://w3id.org/dice-research/qa-bench#hasQuestionWord", false, // NamedClass.TOP), // new SimpleQuantifiedRole(true, "http://w3id.org/dice-research/qa-bench#hasQuery", false, @@ -305,20 +316,15 @@ public static void main(String[] args) throws Exception { // NamedClass.TOP), // new NamedClass("http://www.w3.org/2004/02/skos/core#Concept"), // new NamedClass("http://dbpedia.org/ontology/Agent")))))); -// ⊓ -// ∃.∃.( -// http://dbpedia.org/ontology/Company -// ⊔ -// http://dbpedia.org/ontology/Location -// ⊔ -// http://dbpedia.org/ontology/MusicGenre -// ⊔ -// (∃http://xmlns.com/foaf/0.1/name.⊤⊓http://www.w3.org/2004/02/skos/core#Concept⊓http://dbpedia.org/ontology/Agent) -// ⊔ -// http://dbpedia.org/ontology/Currency -// ) +// ∀http://w3id.org/dice-research/qa-bench#hasQuestionWord.⊥ +// ⊔ +// ( +// ∀http://w3id.org/dice-research/qa-bench#hasLiteralAnswer.⊥ +// ⊓ +// ∀http://w3id.org/dice-research/qa-bench#hasIRIAnswer.⊥ +// ) // LearningProblem prob = problems.iterator().next(); -// System.out.println(suggestor.suggestProperty(prob.getPositiveExamples(), prob.getNegativeExamples(), ce)); +// System.out.println(suggestor.suggestClass(prob.getPositiveExamples(), prob.getNegativeExamples(), ce)); // System.out.println(suggestor.scoreExpression(ce, prob.getPositiveExamples(), prob.getNegativeExamples())); // System.out.println(ce); // ce = (new NegatingVisitor()).negateExpression(ce); diff --git a/src/main/java/org/dice_research/cel/refine/suggest/sparql/FilterNotExistsChecker.java b/src/main/java/org/dice_research/cel/refine/suggest/sparql/FilterNotExistsChecker.java new file mode 100644 index 0000000..2a3a4f1 --- /dev/null +++ b/src/main/java/org/dice_research/cel/refine/suggest/sparql/FilterNotExistsChecker.java @@ -0,0 +1,50 @@ +package org.dice_research.cel.refine.suggest.sparql; + +import org.dice_research.cel.expression.ClassExpression; +import org.dice_research.cel.expression.ClassExpressionVisitingCreator; +import org.dice_research.cel.expression.Junction; +import org.dice_research.cel.expression.NamedClass; +import org.dice_research.cel.expression.SimpleQuantifiedRole; + +/** + * This class is a visitor that returns {@code true} if the given class + * expression should not be put into a {@code FILTER NOT EXISTS} (FNE) statement + * since the statement itself will consist of one (or several) FNE statements. + * Instead, such an expression should be simply negated. + * + * For example, trying to add an FNE statement with the expression ∀r.⊥ leads to + * an FNE statement within an FNE, without any additional triple pattern in the + * outer filter. That means that the variables within the filter and outside of + * the filter are not connected, anymore. Hence, it is easier to add ∃r.⊤ + * instead. The same holds for negated, named classes (¬A) or a conjunction of + * these two types of statements. + * + * Note that the given statement should already have been preprocessed for being + * transformed into a SPARQL query. + * + * @author Michael Röder (michael.roeder@uni-paderborn.de) + * + */ +public class FilterNotExistsChecker implements ClassExpressionVisitingCreator { + + @Override + public Boolean visitNamedClass(NamedClass node) { + return node.isNegated(); + } + + @Override + public Boolean visitJunction(Junction node) { + for (ClassExpression child : node.getChildren()) { + if (!child.accept(this)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean visitSimpleQuantificationRole(SimpleQuantifiedRole node) { + return !node.isExists(); + } + +} diff --git a/src/main/java/org/dice_research/cel/refine/suggest/sparql/SparqlBuildingVisitor.java b/src/main/java/org/dice_research/cel/refine/suggest/sparql/SparqlBuildingVisitor.java index f5729a4..4cd84f8 100644 --- a/src/main/java/org/dice_research/cel/refine/suggest/sparql/SparqlBuildingVisitor.java +++ b/src/main/java/org/dice_research/cel/refine/suggest/sparql/SparqlBuildingVisitor.java @@ -41,6 +41,7 @@ public class SparqlBuildingVisitor implements ClassExpressionVisitor { protected Function variableToStmtOnMarkedPosition; protected NegatingVisitor negator = new NegatingVisitor(); protected DisjunctionCheckingVisitor checker = new DisjunctionCheckingVisitor(); + protected FilterNotExistsChecker fneChecker = new FilterNotExistsChecker(); protected ExpressionPreProcessor preprocessor = new ExpressionPreProcessor(); /** @@ -206,9 +207,7 @@ public void visitNotExistsFilter(ClassExpression filterExpression) { isRoot = false; for (ClassExpression expression : expressions) { // If this is an expression would create a FILTER NON EXISTS statement - if (((expression instanceof NamedClass) && (((NamedClass) expression).isNegated())) - || ((expression instanceof SimpleQuantifiedRole) - && (!((SimpleQuantifiedRole) expression).isExists()))) { + if (expression.accept(fneChecker)) { // Simply negate the statement and add it ClassExpression negated = negator.negateExpression(expression); negated = preprocessor.preprocess(negated); diff --git a/src/test/java/org/dice_research/cel/refine/suggest/sparql/FilterNotExistsCheckerTest.java b/src/test/java/org/dice_research/cel/refine/suggest/sparql/FilterNotExistsCheckerTest.java new file mode 100644 index 0000000..8eaea28 --- /dev/null +++ b/src/test/java/org/dice_research/cel/refine/suggest/sparql/FilterNotExistsCheckerTest.java @@ -0,0 +1,64 @@ +package org.dice_research.cel.refine.suggest.sparql; + +import java.util.ArrayList; +import java.util.List; + +import org.dice_research.cel.expression.ClassExpression; +import org.dice_research.cel.expression.Junction; +import org.dice_research.cel.expression.NamedClass; +import org.dice_research.cel.expression.SimpleQuantifiedRole; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class FilterNotExistsCheckerTest { + + private ClassExpression givenExpression; + private Boolean expectedResult; + + public FilterNotExistsCheckerTest(ClassExpression givenExpression, Boolean expectedResult) { + super(); + this.givenExpression = givenExpression; + this.expectedResult = expectedResult; + } + + @Test + public void test() { + FilterNotExistsChecker checker = new FilterNotExistsChecker(); + if (expectedResult) { + Assert.assertTrue(givenExpression.accept(checker)); + } else { + Assert.assertFalse(givenExpression.accept(checker)); + } + } + + @Parameters + public static List parameters() { + List testCases = new ArrayList<>(); + + testCases.add(new Object[] { new NamedClass("A"), Boolean.FALSE }); + testCases.add(new Object[] { new NamedClass("A", true), Boolean.TRUE }); + testCases.add(new Object[] { new SimpleQuantifiedRole(true, "r", false, new NamedClass("A")), Boolean.FALSE }); + testCases.add(new Object[] { new SimpleQuantifiedRole(false, "r", false, new NamedClass("A")), Boolean.TRUE }); + + testCases.add(new Object[] { new Junction(true, new NamedClass("A"), new NamedClass("B")), Boolean.FALSE }); + testCases.add( + new Object[] { new Junction(true, new NamedClass("A", true), new NamedClass("B")), Boolean.FALSE }); + testCases.add( + new Object[] { new Junction(true, new NamedClass("A"), new NamedClass("B", true)), Boolean.FALSE }); + testCases.add(new Object[] { new Junction(true, new NamedClass("A", true), new NamedClass("B", true)), + Boolean.TRUE }); + testCases + .add(new Object[] { + new Junction(true, new NamedClass("A", true), + new Junction(true, new NamedClass("B", true), + new SimpleQuantifiedRole(false, "r", false, new NamedClass("A")))), + Boolean.TRUE }); + + return testCases; + } + +}