Skip to content

Commit

Permalink
Change role chain (PPI) from property set to sequence (ikmdev#54)
Browse files Browse the repository at this point in the history
* Add tinkar test data unpack for snomed intl 20241001

* Add ITs for snomed intl 20241001

* Change role chain (PPI) from property set to sequence

* Add data property type. Fix parse issue with dadaHasValue.

---------

Co-authored-by: stenkarl <[email protected]>
  • Loading branch information
emays and stenkarl authored Oct 29, 2024
1 parent 43bfcfe commit 312a56b
Show file tree
Hide file tree
Showing 8 changed files with 462 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
import static java.io.StreamTokenizer.*;

public class SctOwlUtilities {

private static final Logger LOG = LoggerFactory.getLogger(SctOwlUtilities.class);

public static final String TRANSITIVEOBJECTPROPERTY = "transitiveobjectproperty";
public static final String PREFIX = "prefix";
public static final String ONTOLOGY = "ontology";
Expand Down Expand Up @@ -84,7 +86,7 @@ public static LogicalExpression sctToLogicalExpression(String owlClassExpression


String originalExpression = owlClassExpressionsToProcess + " " + owlPropertyExpressionsToProcess;

final LogicalExpressionBuilder leb = new LogicalExpressionBuilder();


Expand Down
14 changes: 14 additions & 0 deletions reasoner/reasoner-elk-snomed/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@
<version>${snomed-test-data.version}</version>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>${snomed-test-data.groupid}</groupId>
<artifactId>
snomed-test-data-intl-20241001</artifactId>
<version>${snomed-test-data.version}</version>
<type>zip</type>
</artifactItem>
</artifactItems>
<outputDirectory>
${project.build.directory}/data</outputDirectory>
Expand All @@ -92,6 +99,13 @@
<!-- <version>2024.10.01</version>-->
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>${reasoner-test-data.groupid}</groupId>
<artifactId>
tinkar-test-data-snomed-intl-20241001</artifactId>
<version>2024.10.18</version>
<type>zip</type>
</artifactItem>
</artifactItems>
<outputDirectory>
${project.build.directory}/db</outputDirectory>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import dev.ikm.elk.snomed.SnomedIds;
import dev.ikm.elk.snomed.model.Concept;
import dev.ikm.elk.snomed.model.ConcreteRole;
import dev.ikm.elk.snomed.model.ConcreteRole.ValueType;
Expand All @@ -35,6 +36,7 @@
import dev.ikm.tinkar.common.id.PublicId;
import dev.ikm.tinkar.common.service.PrimitiveData;
import dev.ikm.tinkar.common.service.TrackingCallable;
import dev.ikm.tinkar.common.util.uuid.UuidUtil;
import dev.ikm.tinkar.coordinate.logic.LogicCoordinateRecord;
import dev.ikm.tinkar.coordinate.view.calculator.ViewCalculator;
import dev.ikm.tinkar.entity.graph.DiTreeEntity;
Expand Down Expand Up @@ -204,25 +206,38 @@ private void processPropertySet(EntityVertex propertySetNode, int conceptNid, Di
for (EntityVertex node : definition.successors(child)) {
switch (getMeaning(node)) {
case CONCEPT -> {
RoleType roleType = data.getOrCreateRoleType(conceptNid);
ConceptFacade nodeConcept = node.propertyFast(TinkarTerm.CONCEPT_REFERENCE);
if (nodeConcept.nid() == TinkarTerm.TRANSITIVE_PROPERTY.nid()) {
roleType.setTransitive(true);
} else if (nodeConcept.nid() == TinkarTerm.REFLEXIVE_PROPERTY.nid()) {
roleType.setReflexive(true);
// This won't work if SNOMED introduces data property hierarchy
// LOG.info("UUID for " + SnomedIds.concept_model_data_attribute + " "
// + UuidUtil.fromSNOMED("" + SnomedIds.concept_model_data_attribute));
// if (nodeConcept.nid() == ElkSnomedData.getNid(SnomedIds.concept_model_data_attribute)) {
if (nodeConcept.nid() == TinkarTerm.CONCEPT_MODEL_DATA_ATTRIBUTE.nid()) {
ConcreteRoleType roleType = data.getOrCreateConcreteRoleType(conceptNid);
roleType.addSuperConcreteRoleType(data.getOrCreateConcreteRoleType(nodeConcept.nid()));
} else {
roleType.addSuperRoleType(data.getOrCreateRoleType(nodeConcept.nid()));
RoleType roleType = data.getOrCreateRoleType(conceptNid);
if (nodeConcept.nid() == TinkarTerm.TRANSITIVE_PROPERTY.nid()) {
roleType.setTransitive(true);
} else if (nodeConcept.nid() == TinkarTerm.REFLEXIVE_PROPERTY.nid()) {
roleType.setReflexive(true);
} else {
roleType.addSuperRoleType(data.getOrCreateRoleType(nodeConcept.nid()));
}
}
}
case PROPERTY_PATTERN_IMPLICATION -> {
LOG.info("PropertySet: " + PrimitiveData.text(conceptNid) + " " + propertySetNode + "\n" + definition);
// LOG.info("PropertySet: " + PrimitiveData.text(conceptNid) + " " + propertySetNode + "\n" + definition);
RoleType roleType = data.getOrCreateRoleType(conceptNid);
// TODO: update to new concept binding: Property sequence implication...
ConceptFacade ppi = node.propertyFast(TinkarTerm.PROPERTY_PATTERN_IMPLICATION);
if (ppi.nid() != conceptNid)
throw new IllegalStateException(
"Property chain malformed. Concept: " + conceptNid + " definition: " + definition);
IntIdList ps = node.propertyFast(TinkarTerm.PROPERTY_SEQUENCE);
if (ps == null)
throw new IllegalStateException(
"Property chain malformed. Expected " + TinkarTerm.PROPERTY_SEQUENCE.description()
+ " Concept: " + conceptNid + " definition: " + definition);
if (ps.size() != 2)
throw new IllegalStateException("Property chain " + ps.size() + " != 2. Concept: " + conceptNid
+ " definition: " + definition);
Expand All @@ -234,8 +249,8 @@ private void processPropertySet(EntityVertex propertySetNode, int conceptNid, Di
if (!roleType.equals(prop1))
throw new IllegalStateException("This is a bug.");
roleType.setChained(prop2);
LOG.info("PPI: " + PrimitiveData.text((int) prop1.getId()) + " "
+ PrimitiveData.text((int) prop1.getChained().getId()));
// LOG.info("PPI: " + PrimitiveData.text((int) prop1.getId()) + " -> "
// + PrimitiveData.text((int) prop1.getChained().getId()));
}
default -> throw new UnsupportedOperationException("Can't handle: " + node + " in: " + definition);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright © 2015 Integrated Knowledge Management ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.ikm.tinkar.reasoner.elksnomed;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import dev.ikm.elk.snomed.SnomedIds;
import dev.ikm.elk.snomed.SnomedIsa;
import dev.ikm.elk.snomed.SnomedOntology;
import dev.ikm.elk.snomed.SnomedOntologyReasoner;
import dev.ikm.elk.snomed.model.Concept;
import dev.ikm.tinkar.common.service.PrimitiveData;
import dev.ikm.tinkar.common.util.uuid.UuidUtil;

public class SnomedINTL20241001ElkSnomedClassifierTestIT extends SnomedINTL20241001ElkSnomedTestBase {

private static final Logger LOG = LoggerFactory.getLogger(SnomedINTL20241001ElkSnomedClassifierTestIT.class);

@Test
public void supercs() throws Exception {
ArrayList<String> lines = runSnomedReasoner();
assertEquals(634059, lines.size());
}

@Test
public void supercsService() throws Exception {
ArrayList<String> lines = runSnomedReasonerService();
assertEquals(634059, lines.size());
}

private HashMap<Integer, Long> nid_sctid_map;

private Set<Long> toSctids(Set<Long> nids) {
return nids.stream().map(x -> nid_sctid_map.get(x.intValue())).collect(Collectors.toSet());
}

@Test
public void isas() throws Exception {
LOG.info("runSnomedReasoner");
ElkSnomedData data = buildSnomedData();
LOG.info("Create ontology");
SnomedOntology ontology = new SnomedOntology(data.getConcepts(), data.getRoleTypes(), List.of());
LOG.info("Create reasoner");
SnomedOntologyReasoner reasoner = SnomedOntologyReasoner.create(ontology);
TreeSet<Long> misses = new TreeSet<>();
TreeSet<Long> other_misses = new TreeSet<>();
int non_snomed_cnt = 0;
int miss_cnt = 0;
int pharma_miss_cnt = 0;
int other_miss_cnt = 0;
SnomedIsa isas = SnomedIsa.init(rels_file);
nid_sctid_map = new HashMap<>();
for (long sctid : isas.getOrderedConcepts()) {
int nid = ElkSnomedData.getNid(sctid);
nid_sctid_map.put(nid, sctid);
}
for (Concept con : ontology.getConcepts()) {
long nid = con.getId();
Set<Long> sups = toSctids(reasoner.getSuperConcepts(nid));
Long sctid = nid_sctid_map.get((int) nid);
if (sctid == null) {
non_snomed_cnt++;
continue;
}
Set<Long> parents = isas.getParents(sctid);
if (sctid == SnomedIds.root) {
assertTrue(parents.isEmpty());
} else {
assertNotNull(parents);
}
if (!parents.equals(sups)) {
misses.add(sctid);
miss_cnt++;
if (isas.hasAncestor(sctid, 373873005)) {
// 373873005 |Pharmaceutical / biologic product (product)|
pharma_miss_cnt++;
} else if (isas.hasAncestor(sctid, 127785005)) {
// 127785005 |Administration of substance to produce immunity, either active or
// passive (procedure)|
} else if (isas.hasAncestor(sctid, 713404003)) {
// 713404003 |Vaccination given (situation)|
} else if (isas.hasAncestor(sctid, 591000119102l)) {
// 591000119102 |Vaccine declined by patient (situation)|
} else if (isas.hasAncestor(sctid, 90351000119108l)) {
// 90351000119108 |Vaccination not done (situation)|
} else if (isas.hasAncestor(sctid, 293104008)) {
// 293104008 |Adverse reaction to component of vaccine product (disorder)|
} else if (isas.hasAncestor(sctid, 266758009)) {
// 266758009 |Immunization contraindicated (situation)|
} else {
other_misses.add(sctid);
other_miss_cnt++;
}
}
}
isas.getOrderedConcepts().stream().filter(other_misses::contains) //
.limit(10) //
.forEach((sctid) -> {
UUID uuid = UuidUtil.fromSNOMED("" + sctid);
int nid = PrimitiveData.nid(uuid);
LOG.error("Miss: " + sctid + " " + PrimitiveData.text(nid));
Set<Long> sups = toSctids(reasoner.getSuperConcepts(nid));
Set<Long> parents = isas.getParents(sctid);
HashSet<Long> par = new HashSet<>(parents);
par.removeAll(sups);
HashSet<Long> sup = new HashSet<>(sups);
sup.removeAll(parents);
LOG.error("Sno: " + par);
LOG.error("Elk: " + sup);
});
LOG.error("Miss cnt: " + miss_cnt);
LOG.error("Pharma cnt: " + pharma_miss_cnt);
LOG.error("Other cnt: " + other_miss_cnt);
assertEquals(282, non_snomed_cnt);
// TODO this should be 0 after all the data issues are fixed
assertEquals(21065, miss_cnt);
assertEquals(20815, pharma_miss_cnt);
assertEquals(194, other_miss_cnt);
}

}
Loading

0 comments on commit 312a56b

Please sign in to comment.