diff --git a/pom.xml b/pom.xml
index d317bc29..e2140368 100644
--- a/pom.xml
+++ b/pom.xml
@@ -117,7 +117,7 @@
0.14-r6
0.9.31-r8
- 0.37.0-SNAPSHOT
+ 0.36.0
4.7.6
diff --git a/reasoner/reasoner-elk-snomed/src/test/java/dev/ikm/tinkar/reasoner/elksnomed/ElkSnomedClassifierTestBase.java b/reasoner/reasoner-elk-snomed/src/test/java/dev/ikm/tinkar/reasoner/elksnomed/ElkSnomedClassifierTestBase.java
index c22c9f6b..aa3f338f 100644
--- a/reasoner/reasoner-elk-snomed/src/test/java/dev/ikm/tinkar/reasoner/elksnomed/ElkSnomedClassifierTestBase.java
+++ b/reasoner/reasoner-elk-snomed/src/test/java/dev/ikm/tinkar/reasoner/elksnomed/ElkSnomedClassifierTestBase.java
@@ -74,6 +74,7 @@ public void nnfService() throws Exception {
int nid = ElkSnomedData.getNid(404785009);
LogicalExpression nnf = rs.getNecessaryNormalForm(nid);
LOG.info("NNF: " + nid + " " + nnf);
+ rs.writeInferredResults();
}
private HashMap nid_sctid_map;
diff --git a/reasoner/reasoner-service/src/main/java/dev/ikm/tinkar/reasoner/service/InferredResultsWriter.java b/reasoner/reasoner-service/src/main/java/dev/ikm/tinkar/reasoner/service/InferredResultsWriter.java
new file mode 100644
index 00000000..f5e7c568
--- /dev/null
+++ b/reasoner/reasoner-service/src/main/java/dev/ikm/tinkar/reasoner/service/InferredResultsWriter.java
@@ -0,0 +1,218 @@
+package dev.ikm.tinkar.reasoner.service;
+
+import java.util.Arrays;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.collections.api.factory.Lists;
+import org.eclipse.collections.api.list.ImmutableList;
+import org.eclipse.collections.api.list.primitive.ImmutableIntList;
+import org.eclipse.collections.api.set.primitive.ImmutableIntSet;
+import org.eclipse.collections.impl.factory.primitive.IntLists;
+import org.eclipse.collections.impl.factory.primitive.IntSets;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import dev.ikm.tinkar.common.id.IntIdSet;
+import dev.ikm.tinkar.common.id.IntIds;
+import dev.ikm.tinkar.common.service.PrimitiveData;
+import dev.ikm.tinkar.common.sets.ConcurrentHashSet;
+import dev.ikm.tinkar.common.util.time.MultipleEndpointTimer;
+import dev.ikm.tinkar.common.util.uuid.UuidT5Generator;
+import dev.ikm.tinkar.coordinate.stamp.calculator.Latest;
+import dev.ikm.tinkar.coordinate.view.ViewCoordinateRecord;
+import dev.ikm.tinkar.entity.Entity;
+import dev.ikm.tinkar.entity.EntityService;
+import dev.ikm.tinkar.entity.EntityVersion;
+import dev.ikm.tinkar.entity.RecordListBuilder;
+import dev.ikm.tinkar.entity.SemanticEntityVersion;
+import dev.ikm.tinkar.entity.SemanticRecord;
+import dev.ikm.tinkar.entity.SemanticRecordBuilder;
+import dev.ikm.tinkar.entity.SemanticVersionRecord;
+import dev.ikm.tinkar.entity.StampEntity;
+import dev.ikm.tinkar.entity.graph.DiTreeEntity;
+import dev.ikm.tinkar.entity.graph.adaptor.axiom.LogicalExpression;
+import dev.ikm.tinkar.entity.graph.isomorphic.IsomorphicResults;
+import dev.ikm.tinkar.entity.transaction.Transaction;
+import dev.ikm.tinkar.terms.State;
+import dev.ikm.tinkar.terms.TinkarTerm;
+
+public class InferredResultsWriter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InferredResultsWriter.class);
+
+ private ReasonerService rs;
+
+ private Transaction updateTransaction;
+
+ private int updateStampNid;
+
+ private int inferredPatternNid;
+
+ private int inferredNavigationPatternNid;
+
+ private MultipleEndpointTimer multipleEndpointTimer;
+
+ private ConcurrentHashSet equivalentSets;
+
+ private ConcurrentHashSet conceptsWithInferredChanges;
+
+ private ConcurrentHashSet conceptsWithNavigationChanges;
+
+ private AtomicInteger axiomDataNotFoundCounter;
+
+ public InferredResultsWriter(ReasonerService rs) {
+ super();
+ this.rs = rs;
+ }
+
+ private ViewCoordinateRecord getViewCoordinateRecord() {
+ return rs.getViewCalculator().viewCoordinateRecord();
+ }
+
+ private void processSemantic(Entity extends EntityVersion> entity) {
+ updateTransaction.addComponent(entity);
+ Entity.provider().putEntity(entity);
+ }
+
+ public ClassifierResults write() {
+ updateTransaction = Transaction.make("Committing classification");
+ EntityService.get().beginLoadPhase();
+ try {
+ StampEntity> updateStamp = updateTransaction.getStamp(State.ACTIVE,
+ getViewCoordinateRecord().getAuthorNidForChanges(), getViewCoordinateRecord().getDefaultModuleNid(),
+ getViewCoordinateRecord().getDefaultPathNid());
+ updateStampNid = updateStamp.nid();
+ inferredPatternNid = getViewCoordinateRecord().logicCoordinate().inferredAxiomsPatternNid();
+ inferredNavigationPatternNid = TinkarTerm.INFERRED_NAVIGATION_PATTERN.nid();
+ multipleEndpointTimer = new MultipleEndpointTimer<>(IsomorphicResults.EndPoints.class);
+ equivalentSets = new ConcurrentHashSet<>();
+ conceptsWithInferredChanges = new ConcurrentHashSet<>();
+ conceptsWithNavigationChanges = new ConcurrentHashSet<>();
+ axiomDataNotFoundCounter = new AtomicInteger();
+ rs.getReasonerConceptSet().primitiveParallelStream().forEach(conceptNid -> {
+ updateEquivalentSets(conceptNid);
+ writeNNF(conceptNid);
+ writeNavigation(conceptNid);
+ });
+ updateTransaction.commit();
+ } finally {
+ EntityService.get().endLoadPhase();
+ }
+ LOG.info("Inferred changes: " + conceptsWithInferredChanges.size());
+ LOG.info("Navigation changes: " + conceptsWithNavigationChanges.size());
+ LOG.info("NavigationSemantics processed not in AxiomData: " + axiomDataNotFoundCounter.get());
+ ViewCoordinateRecord commitCoordinate = getViewCoordinateRecord().withStampCoordinate(
+ getViewCoordinateRecord().stampCoordinate().withStampPositionTime(updateTransaction.commitTime()));
+ return new ClassifierResults(rs.getReasonerConceptSet(),
+ IntLists.immutable.ofAll(conceptsWithInferredChanges.stream().sorted().mapToInt(Integer::intValue)),
+ IntLists.immutable.ofAll(conceptsWithNavigationChanges.stream().sorted().mapToInt(Integer::intValue)),
+ equivalentSets, commitCoordinate);
+ }
+
+ private void updateEquivalentSets(int conceptNid) {
+ ImmutableIntSet equivalentNids = rs.getEquivalent(conceptNid);
+ if (equivalentNids == null) {
+ LOG.error("Null node for: {} {} {} will be skipped in inferred results", conceptNid,
+ PrimitiveData.publicId(conceptNid).idString(), PrimitiveData.text(conceptNid));
+ } else if (equivalentNids.size() > 1) {
+ equivalentSets.add(equivalentNids.toSortedList().toImmutable());
+ }
+ }
+
+ private void writeNNF(int conceptNid) {
+ LogicalExpression nnf = rs.getNecessaryNormalForm(conceptNid);
+ ImmutableList