From 053e9b34a7b440f919594033eb255eec1397c75b Mon Sep 17 00:00:00 2001
From: Akira <akira.charoensit@inria.fr>
Date: Wed, 26 Mar 2025 21:51:45 +0100
Subject: [PATCH] (build pass) added estimation method to federated fb

---
 .../keywords/InteGraalKeywords.java           |  3 +-
 .../DefaultChaseForExplanations.java          |  5 +-
 .../fr/boreal/test/explanation/TestData.java  |  4 +-
 .../MowlOntologyTest.java                     |  2 +-
 .../FactSupport_MowlOntologyTest.java         |  5 +-
 .../KBSupport_MowlOntologyTest.java           | 28 ++++++----
 .../forward_chaining/chase/ChaseBuilder.java  |  9 ++++
 .../rule_scheduler/ByPredicateScheduler.java  | 54 +++++++++++++++++++
 .../src/main/java/module-info.java            |  3 +-
 .../main/java/fr/boreal/grd/impl/GRDImpl.java |  7 ++-
 .../fr/boreal/model/kb/impl/RuleBaseImpl.java |  2 +-
 .../fr/boreal/views/FederatedFactBase.java    | 51 ++++++++++++++++--
 12 files changed, 146 insertions(+), 27 deletions(-)
 create mode 100644 integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_scheduler/ByPredicateScheduler.java

diff --git a/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java b/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java
index 21ea5f11b..5fb5f66de 100644
--- a/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java
+++ b/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java
@@ -350,7 +350,8 @@ public enum InteGraalKeywords {
                     /**
                      * GRD Scheduler
                      */
-                    GRD
+                    GRD,
+                    BY_PREDICATE
                 }
 
                 /**
diff --git a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/DefaultChaseForExplanations.java b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/DefaultChaseForExplanations.java
index bdbe4772c..54986fbe0 100644
--- a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/DefaultChaseForExplanations.java
+++ b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/DefaultChaseForExplanations.java
@@ -19,10 +19,9 @@ public class DefaultChaseForExplanations {
 
     public static Chase chase(FactBase fb, RuleBase rb) {
         Chase chase = ChaseBuilder.defaultBuilder(fb, rb)
-                .useSemiObliviousChecker()
+                .useObliviousChecker()
                 .useNaiveComputer()
-                //.useGRDRuleScheduler()
-                .useNaiveRuleScheduler()
+                .useByPredicateRuleScheduler()
                 .useMultiThreadRuleApplier()
                 .build().get();
         chase.execute();
diff --git a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/TestData.java b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/TestData.java
index c73144ba6..beb3a9ec4 100644
--- a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/TestData.java
+++ b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/TestData.java
@@ -125,8 +125,8 @@ public class TestData {
             "Ontology1260916270538",
 //            "platformOntology",
 //            "snoopy",
-            "transitive-ancestor",
-//            "catalogue",
+//            "transitive-ancestor",
+//            "catalogue"
             "ddex"
 //            "ncbi_rank",
 //            "oil",
diff --git a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_has_explanation/MowlOntologyTest.java b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_has_explanation/MowlOntologyTest.java
index 8b3d766e8..2181b865b 100644
--- a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_has_explanation/MowlOntologyTest.java
+++ b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_has_explanation/MowlOntologyTest.java
@@ -30,7 +30,7 @@ import java.util.stream.Stream;
 public class MowlOntologyTest {
 
     static String mowl_bench_path = "./src/test/resources/mowl-bench-main/";
-    static List<String> mowl_bench_datasets = TestData.all_mowl_bench_datasets;
+    static List<String> mowl_bench_datasets = TestData.hard_mowl_bench_datasets;
 
     enum AtomicQueryExplainerType {
         STATIC_GRI_FB_MARCO,
diff --git a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/FactSupport_MowlOntologyTest.java b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/FactSupport_MowlOntologyTest.java
index 78a85f7bf..7957b425d 100644
--- a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/FactSupport_MowlOntologyTest.java
+++ b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/FactSupport_MowlOntologyTest.java
@@ -2,6 +2,7 @@ package fr.boreal.test.explanation.check_same_explanation;
 
 import fr.boreal.explanation.InternalDLGPParser;
 import fr.boreal.explanation.api.explainers.AtomicQueryExplainer;
+import fr.boreal.explanation.kb_gri.explainers.incremental_gri.FactSupportExplainer_IncrementalKBGRI;
 import fr.boreal.explanation.kb_gri.explainers.static_gri.FactSupportExplainer_KBGRI;
 import fr.boreal.explanation.solving_enumerating.sat4j.Sat4JSolver;
 import fr.boreal.explanation.tracker_gri.explainers.FactSupportExplainer_TrackerGRI;
@@ -30,7 +31,8 @@ public class FactSupport_MowlOntologyTest {
         STATIC_GRI_FACT_MARCO,
         STATIC_GRI_FACT_S4J,
         TRACKER_STATIC_GRI_FACT_MARCO,
-        TRACKER_STATIC_GRI_FACT_S4J
+        TRACKER_STATIC_GRI_FACT_S4J,
+        INCREMENTAL_GRI_FACT_MARCO
     }
 
     static private Map<Atom,Integer> nbExplanations = new HashMap<>();
@@ -44,6 +46,7 @@ public class FactSupport_MowlOntologyTest {
             case STATIC_GRI_FACT_S4J -> new FactSupportExplainer_KBGRI(kb, new Sat4JSolver());
             case TRACKER_STATIC_GRI_FACT_MARCO -> new FactSupportExplainer_TrackerGRI(kb);
             case TRACKER_STATIC_GRI_FACT_S4J -> new FactSupportExplainer_TrackerGRI(kb, new Sat4JSolver());
+            case INCREMENTAL_GRI_FACT_MARCO -> new FactSupportExplainer_IncrementalKBGRI(kb);
         };
     }
 
diff --git a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/KBSupport_MowlOntologyTest.java b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/KBSupport_MowlOntologyTest.java
index 5ddc14727..79da30fde 100644
--- a/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/KBSupport_MowlOntologyTest.java
+++ b/integraal/integraal-explanation/src/test/java/fr/boreal/test/explanation/check_same_explanation/KBSupport_MowlOntologyTest.java
@@ -26,18 +26,18 @@ import java.util.stream.Stream;
 public class KBSupport_MowlOntologyTest {
 
     static String mowl_bench_path =  TestData.mowl_bench_path;
-    static List<String> mowl_bench_datasets = TestData.default_mowl_bench_datasets;
+    static List<String> mowl_bench_datasets = TestData.hard_mowl_bench_datasets;
 
     enum AtomicQueryExplainerType {
         STATIC_GRI_KB_MARCO,
-        STATIC_GRI_KB_S4J,
-        TRACKER_STATIC_GRI_KB_MARCO,
-        TRACKER_STATIC_GRI_KB_S4J,
-        INCREMENTAL_GRI_KB_MARCO
+        STATIC_GRI_KB_S4J//,
+//        TRACKER_STATIC_GRI_KB_MARCO,
+//        TRACKER_STATIC_GRI_KB_S4J,
+//        INCREMENTAL_GRI_KB_MARCO
     }
 
     static private Map<Pair<String,Atom>,Integer> nbExplanations = new HashMap<>();
-    static private Map<Atom, Set<?>> queryToExplanations = new HashMap<>();
+    static private Map<Pair<String,Atom>, Set<?>> queryToExplanations = new HashMap<>();
 
     static AtomicQueryExplainer<?> getExplainer(
             AtomicQueryExplainerType type,
@@ -45,9 +45,9 @@ public class KBSupport_MowlOntologyTest {
         return switch (type) {
             case STATIC_GRI_KB_MARCO -> new KBSupportExplainer_KBGRI(kb);
             case STATIC_GRI_KB_S4J -> new KBSupportExplainer_KBGRI(kb, new Sat4JSolver());
-            case TRACKER_STATIC_GRI_KB_MARCO -> new KBSupportExplainer_TrackerGRI(kb);
-            case TRACKER_STATIC_GRI_KB_S4J -> new KBSupportExplainer_TrackerGRI(kb, new Sat4JSolver());
-            case INCREMENTAL_GRI_KB_MARCO -> new KBSupportExplainer_IncrementalKBGRI(kb);
+//            case TRACKER_STATIC_GRI_KB_MARCO -> new KBSupportExplainer_TrackerGRI(kb);
+//            case TRACKER_STATIC_GRI_KB_S4J -> new KBSupportExplainer_TrackerGRI(kb, new Sat4JSolver());
+//            case INCREMENTAL_GRI_KB_MARCO -> new KBSupportExplainer_IncrementalKBGRI(kb);
         };
     }
 
@@ -92,12 +92,18 @@ public class KBSupport_MowlOntologyTest {
 
             var key = Pair.of(ontology_name,query);
             if (nbExplanations.containsKey(key)) {
+                System.out.println(queryToExplanations);
+                System.out.println(nbExplanations);
+
                 Assertions.assertTrue(explanations.size() == nbExplanations.get(key),
                         "Explainer "+explainerType+" gives "+explanations.size()+" explanations whereas Marco gives "+nbExplanations.get(key)+" for query: " + query +
-                 "\nMarco:" + queryToExplanations.get(query) + "\n" + explainerType + explanations);
+                 "\nMarco:" + queryToExplanations.get(key) + "\n" + explainerType + explanations);
             } else {
                 nbExplanations.put(key, explanations.size());
-                queryToExplanations.put(query,explanations);
+                queryToExplanations.put(key, new HashSet<>(explanations));
+
+                System.out.println("Explanations: "+queryToExplanations);
+                System.out.println("Expl number: "+nbExplanations);
             }
         }
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java
index 9b31c6f8a..d7c648c2a 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java
@@ -26,6 +26,7 @@ import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.NaiveTrigg
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.SemiNaiveComputer;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.TriggerComputer;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.TwoStepComputer;
+import fr.boreal.forward_chaining.chase.rule_scheduler.ByPredicateScheduler;
 import fr.boreal.forward_chaining.chase.rule_scheduler.GRDScheduler;
 import fr.boreal.forward_chaining.chase.rule_scheduler.NaiveScheduler;
 import fr.boreal.forward_chaining.chase.rule_scheduler.RuleScheduler;
@@ -208,6 +209,9 @@ public class ChaseBuilder {
                 case GRD:
                     this.setRuleScheduler(new GRDScheduler(this.rb));
                     break;
+                case BY_PREDICATE:
+                    this.setRuleScheduler(new ByPredicateScheduler(this.rb));
+                    break;
             }
         }
         if (this.eval == null) {
@@ -393,6 +397,11 @@ public class ChaseBuilder {
         return this;
     }
 
+    public ChaseBuilder useByPredicateRuleScheduler() {
+        this.scheduler = InteGraalKeywords.Algorithms.Parameters.Chase.Scheduler.BY_PREDICATE;
+        return this;
+    }
+
     // Body To Query transformers //
 
     /**
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_scheduler/ByPredicateScheduler.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_scheduler/ByPredicateScheduler.java
new file mode 100644
index 000000000..79764a9d7
--- /dev/null
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_scheduler/ByPredicateScheduler.java
@@ -0,0 +1,54 @@
+package fr.boreal.forward_chaining.chase.rule_scheduler;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+import fr.boreal.configuration.parameters.IGParameter;
+import fr.boreal.grd.api.GraphOfFORuleDependencies;
+import fr.boreal.grd.impl.GRDImpl;
+import fr.boreal.model.kb.api.RuleBase;
+import fr.boreal.model.rule.api.FORule;
+import fr.boreal.configuration.keywords.InteGraalKeywords;
+
+/**
+ * Schedules all the rules that can be triggered by rules applied at the previous step
+ * according to the graph of rule dependencies
+ */
+public class ByPredicateScheduler implements RuleScheduler {
+
+    private RuleBase rb;
+
+    /**
+     * @param rb the rulebase
+     */
+    public ByPredicateScheduler(RuleBase rb) {
+        this.init(rb);
+    }
+
+    @Override
+    public void init(RuleBase rb) {
+        this.rb = rb;
+    }
+
+    @Override
+    public Collection<FORule> getRulesToApply(Collection<FORule> last_applied_rules) {
+        // first call -> should use an optional instead of null
+        if(last_applied_rules == null) {
+            return this.rb.getRules();
+        }
+        return last_applied_rules.parallelStream()
+                .flatMap(rule -> rule.getHead().getPredicates().parallelStream())
+                .distinct()
+                .flatMap(p -> this.rb.getRulesByBodyPredicate(p).parallelStream())
+                .collect(Collectors.toSet());
+    }
+
+    public String describe(){
+        return getCorrespondingParameter().value().toString();
+    }
+
+    public IGParameter<InteGraalKeywords,?> getCorrespondingParameter(){
+        return new IGParameter<>(InteGraalKeywords.SCHEDULER,InteGraalKeywords.Algorithms.Parameters.Chase.Scheduler.GRD);
+    }
+
+}
diff --git a/integraal/integraal-forward-chaining/src/main/java/module-info.java b/integraal/integraal-forward-chaining/src/main/java/module-info.java
index da7ffc998..13aed1ca9 100644
--- a/integraal/integraal-forward-chaining/src/main/java/module-info.java
+++ b/integraal/integraal-forward-chaining/src/main/java/module-info.java
@@ -32,5 +32,6 @@ module fr.boreal.forward_chaining {
 	exports fr.boreal.forward_chaining.chase.rule_scheduler;
 	exports fr.boreal.forward_chaining.chase.treatment;
 	exports fr.boreal.forward_chaining.chase.lineage;
-    exports fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.tracking;
+	exports fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.tracking;
+	exports fr.boreal.forward_chaining.chase.metachase.stratified;
 }
\ No newline at end of file
diff --git a/integraal/integraal-grd/src/main/java/fr/boreal/grd/impl/GRDImpl.java b/integraal/integraal-grd/src/main/java/fr/boreal/grd/impl/GRDImpl.java
index 23f5396eb..ed478db91 100644
--- a/integraal/integraal-grd/src/main/java/fr/boreal/grd/impl/GRDImpl.java
+++ b/integraal/integraal-grd/src/main/java/fr/boreal/grd/impl/GRDImpl.java
@@ -312,8 +312,11 @@ public class GRDImpl extends DirectedPseudograph<FORule, GRDEdge> implements Gra
 				this.computeDependency(r1, r2);
 			}
 		}*/
-		this.vertexSet().parallelStream()
-				.flatMap(r1 -> this.vertexSet().parallelStream().map(r2 -> Pair.of(r1, r2)))
+		this.rulebase.getRules().parallelStream()
+				.flatMap(r1 -> r1.getHead().getPredicates().parallelStream()
+						.flatMap(p -> this.rulebase.getRulesByBodyPredicate(p).parallelStream())
+						.distinct()
+						.map(r2 -> Pair.of(r1, r2)))
 				.forEach(pair -> this.computeDependency(pair.getLeft(), pair.getRight()));
 	}
 
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/kb/impl/RuleBaseImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/kb/impl/RuleBaseImpl.java
index 79ee5f883..4778923fa 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/kb/impl/RuleBaseImpl.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/kb/impl/RuleBaseImpl.java
@@ -82,7 +82,7 @@ public class RuleBaseImpl implements RuleBase {
 	}
 
 	@Override
-	public Collection<FORule> getRulesByBodyPredicate(Predicate p) {
+	public synchronized Collection<FORule> getRulesByBodyPredicate(Predicate p) {
 		if(this.rules_by_body_predicate == null) {
 			this.rules_by_body_predicate = new HashMap<>();
 			for(FORule rule : this.rules) {
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java b/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java
index 37f769c4c..ea5247060 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java
@@ -12,10 +12,7 @@ import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
 import fr.boreal.views.datasource.AbstractViewWrapper;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Stream;
 
 /**
@@ -218,6 +215,52 @@ public class FederatedFactBase implements FactBase {
 		return FactBaseType.GRAAL;
 	}
 
+	private Readable getReadable(Predicate viewPredicate) {
+		Readable r = this.facts_by_storage.get(viewPredicate);
+		if (r == null) {
+			r = this.default_storage;
+		}
+		return r;
+	}
+
+	private Optional<FactBase> getReadableFactbase(Predicate viewPredicate) {
+		Readable r = this.facts_by_storage.get(viewPredicate);
+		if (r == null) {
+			r = this.default_storage;
+		}
+		return r instanceof FactBase ? Optional.of((FactBase) r) : Optional.empty();
+	}
+
+	@Override
+	public Optional<Long> estimateMatchCount(Atom atom) {
+		Optional<FactBase> fb = getReadableFactbase(atom.getPredicate());
+		if (fb.isPresent()) {
+			return fb.get().estimateMatchCount(atom);
+		}
+		return Optional.empty();
+	}
+
+	@Override
+	public Optional<Long> estimateMatchCount(Atom atom, Substitution substitution) {
+		Optional<FactBase> fb = getReadableFactbase(atom.getPredicate());
+		if (fb.isPresent()) {
+			return fb.get().estimateMatchCount(atom, substitution);
+		}
+		return Optional.empty();
+	}
+
+	@Override
+	public boolean canPerformIndexedMatch(Atom atom) {
+		Optional<FactBase> fb = getReadableFactbase(atom.getPredicate());
+        return fb.map(factBase -> factBase.canPerformIndexedMatch(atom)).orElse(false);
+    }
+
+	@Override
+	public boolean canPerformIndexedMatch(Atom atom, Substitution substitution) {
+		Optional<FactBase> fb = getReadableFactbase(atom.getPredicate());
+        return fb.map(factBase -> factBase.canPerformIndexedMatch(atom, substitution)).orElse(false);
+    }
+
 	/////////////////////////////////////////////////
 	// Private methods
 	/////////////////////////////////////////////////
-- 
GitLab