Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions elk-snomed/src/main/java/dev/ikm/elk/snomed/ConceptComparer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* #%L
* ELK Integration with SNOMED
* %%
* Copyright (C) 2023 - 2025 Integrated Knowledge Management
* Copyright (C) 2023 - 2026 Integrated Knowledge Management
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,13 +20,11 @@
* #L%
*/

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.collections.api.factory.primitive.LongSets;
import org.eclipse.collections.api.set.primitive.MutableLongSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -37,7 +35,7 @@
import dev.ikm.elk.snomed.model.RoleGroup;

public class ConceptComparer {
private MutableLongSet mis_match_cons = LongSets.mutable.empty();
private MutableLongSet mis_match_cons = LongSets.mutable.empty();

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

Expand All @@ -53,22 +51,24 @@ public ConceptComparer(SnomedOntology inferredOntology) {
this.inferredOntology = inferredOntology;
}

/**
* Check if a concept ID has mismatches.
* @param conceptId the concept ID to check
* @return true if this concept has recorded mismatches
*/
public boolean hasMismatch(long conceptId) {
return mis_match_cons.contains(conceptId); // Primitive contains - no boxing!
}
/**
* Check if a concept ID has mismatches.
*
* @param conceptId the concept ID to check
* @return true if this concept has recorded mismatches
*/
public boolean hasMismatch(long conceptId) {
return mis_match_cons.contains(conceptId); // Primitive contains - no boxing!
}

/**
* Get all concept IDs with mismatches.
* @return array of concept IDs (no boxing in array)
*/
public long[] getMismatchConceptIds() {
return mis_match_cons.toArray(); // Primitive array - efficient!
}
/**
* Get all concept IDs with mismatches.
*
* @return array of concept IDs (no boxing in array)
*/
public long[] getMismatchConceptIds() {
return mis_match_cons.toArray(); // Primitive array - efficient!
}

public int getMisMatchCount() {
return mis_match_cnt;
Expand Down Expand Up @@ -96,7 +96,7 @@ public boolean compare(Concept concept1, Concept concept2) {
}
if (!match) {
mis_match_cnt++;
mis_match_cons.add(concept1.getId()); // No boxing - primitive add!
mis_match_cons.add(concept1.getId()); // No boxing - primitive add!
if (log_mis_match_detail) {
LOG.info("Concept: " + concept1);
LOG.info("Concept1 parents:");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
*/

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
Expand All @@ -36,7 +35,6 @@
import org.eclipse.collections.api.map.primitive.MutableLongObjectMap;
import org.eclipse.collections.api.set.MutableSet;
import org.eclipse.collections.api.set.primitive.MutableLongSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -107,17 +105,16 @@ protected NecessaryNormalFormBuilder(SnomedOntology snomedOntology, long root, P
}

public static NecessaryNormalFormBuilder create(SnomedOntology snomedOntology,
MutableLongObjectMap<MutableLongSet> superConcepts, // ← Primitive map!
MutableLongObjectMap<MutableLongSet> superRoleTypes, // ← Primitive map!
MutableLongObjectMap<MutableLongSet> superConcepts, // ← Primitive map!
MutableLongObjectMap<MutableLongSet> superRoleTypes, // ← Primitive map!
ProgressUpdater progressUpdater) {
return create(snomedOntology, superConcepts, superRoleTypes, SnomedIds.root, progressUpdater);
}

public static NecessaryNormalFormBuilder create(SnomedOntology snomedOntology,
MutableLongObjectMap<MutableLongSet> superConcepts, // ← Primitive map!
MutableLongObjectMap<MutableLongSet> superRoleTypes, // ← Primitive map!
long root,
ProgressUpdater progressUpdater) {
MutableLongObjectMap<MutableLongSet> superConcepts, // ← Primitive map!
MutableLongObjectMap<MutableLongSet> superRoleTypes, // ← Primitive map!
long root, ProgressUpdater progressUpdater) {
NecessaryNormalFormBuilder nnfb = new NecessaryNormalFormBuilder(snomedOntology, root, progressUpdater);
nnfb.initConcepts(superConcepts);
nnfb.initRoles(superRoleTypes);
Expand All @@ -131,16 +128,16 @@ protected void initSubsumption() {

protected void initConcepts(MutableLongObjectMap<MutableLongSet> superConcepts) {
isa = SnomedIsa.init(superConcepts, root);
MutableLongObjectMap<MutableLongSet> dependentOnConcepts = LongObjectMaps.mutable.ofInitialCapacity(
snomedOntology.getConcepts().size());
MutableLongObjectMap<MutableLongSet> dependentOnConcepts = LongObjectMaps.mutable
.ofInitialCapacity(snomedOntology.getConcepts().size());

for (Concept concept : snomedOntology.getConcepts()) {
dependentOnConcepts.put(concept.getId(), getDependentOnConcepts(concept));
}

SnomedIsa deps = SnomedIsa.init(dependentOnConcepts, root);
deps.getOrderedConcepts().forEach(id -> concepts.add(snomedOntology.getConcept(id)));

LOG.info("Concepts: " + concepts.size());
}

Expand All @@ -151,14 +148,14 @@ protected void initRoles(MutableLongObjectMap<MutableLongSet> superRoles) {
MutableSet<RoleType> superTypes = Sets.mutable.empty();
superRolesTypes.put(rt, superTypes);
superTypes.add(rt);

// Use primitive forEach - no boxing!
superRoles.get(rt.getId()).forEach(sup_id -> {
RoleType sup_rt = snomedOntology.getRoleType(sup_id);
superTypes.add(sup_rt);
});
}

if (log_roles) {
for (Entry<RoleType, MutableSet<RoleType>> es : superRolesTypes.entrySet()) {
RoleType rt = es.getKey();
Expand All @@ -175,9 +172,9 @@ protected void initRoles(MutableLongObjectMap<MutableLongSet> superRoles) {
}

private MutableLongSet getDependentOnConcepts(Concept concept) {
MutableLongSet deps = LongSets.mutable.empty(); // ← Primitive set!
MutableLongSet deps = LongSets.mutable.empty(); // ← Primitive set!
long id = concept.getId();
deps.addAll(isa.getParents(id)); // Now returns primitive set
deps.addAll(isa.getParents(id)); // Now returns primitive set
deps.addAll(snomedOntology.getDependentOnConcepts(id, false, false));
return deps;
}
Expand Down Expand Up @@ -222,13 +219,9 @@ public Definition generateNNF(Concept con, boolean useDefining) {
}
MutableSet<Concept> sups;
if (useDefining) {
sups = con.getDefinitions()
.flatCollect(Definition::getSuperConcepts)
.toSet();
sups = con.getDefinitions().flatCollect(Definition::getSuperConcepts).toSet();
} else {
sups = isa.getParents(con.getId())
.collect(snomedOntology::getConcept)
.toSet();
sups = isa.getParents(con.getId()).collect(snomedOntology::getConcept).toSet();
}
sups.forEach(sup -> def.addSuperConcept(sup));
for (Concept sup : sups) {
Expand Down
1 change: 0 additions & 1 deletion elk-snomed/src/main/java/dev/ikm/elk/snomed/SnomedIsa.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.nio.file.Path;
import java.util.stream.Stream;

import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.factory.primitive.LongLists;
import org.eclipse.collections.api.factory.primitive.LongObjectMaps;
import org.eclipse.collections.api.factory.primitive.LongSets;
Expand Down
72 changes: 50 additions & 22 deletions elk-snomed/src/main/java/dev/ikm/elk/snomed/interval/Interval.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dev.ikm.elk.snomed.interval;

import java.math.BigDecimal;

/*-
* #%L
* ELK Integration with SNOMED
Expand Down Expand Up @@ -27,28 +29,36 @@

public class Interval {

private int lowerBound, upperBound;
private BigDecimal lowerBound, upperBound;

private boolean lowerOpen, upperOpen;

private Concept unitOfMeasure;

public int getLowerBound() {
public BigDecimal getLowerBound() {
return lowerBound;
}

public void setLowerBound(int lowerBound) {
public void setLowerBound(BigDecimal lowerBound) {
this.lowerBound = lowerBound;
}

public int getUpperBound() {
public void setLowerBound(int lowerBound) {
this.lowerBound = new BigDecimal(lowerBound);
}

public BigDecimal getUpperBound() {
return upperBound;
}

public void setUpperBound(int upperBound) {
public void setUpperBound(BigDecimal upperBound) {
this.upperBound = upperBound;
}

public void setUpperBound(int upperBound) {
this.upperBound = new BigDecimal(upperBound);
}

public boolean isLowerOpen() {
return lowerOpen;
}
Expand All @@ -73,7 +83,8 @@ public void setUnitOfMeasure(Concept unitOfMeasure) {
this.unitOfMeasure = unitOfMeasure;
}

public Interval(int lowerBound, boolean lowerOpen, int upperBound, boolean upperOpen, Concept unitOfMeasure) {
public Interval(BigDecimal lowerBound, boolean lowerOpen, BigDecimal upperBound, boolean upperOpen,
Concept unitOfMeasure) {
super();
this.lowerBound = lowerBound;
this.lowerOpen = lowerOpen;
Expand All @@ -87,17 +98,19 @@ private Interval() {

public static Interval fromString(String str) {
str = str.replace(" ", "");
String regex = "^(\\[|\\()(\\-?\\d+),(\\-?\\d+)(\\]|\\))(\\-?\\d+)$";
String integer = "(\\-?\\d+)";
String decimal = "(\\-?\\d+(\\.\\d+)?)";
String regex = "^(\\[|\\()" + decimal + "," + decimal + "(\\]|\\))" + integer + "$";
Pattern pat = Pattern.compile(regex);
Matcher mat = pat.matcher(str);
if (!mat.matches())
throw new IllegalArgumentException(str);
Interval ret = new Interval();
ret.lowerOpen = mat.group(1).equals("(");
ret.lowerBound = Integer.parseInt(mat.group(2));
ret.upperBound = Integer.parseInt(mat.group(3));
ret.upperOpen = mat.group(4).equals(")");
long uom = Long.parseLong(mat.group(5));
ret.lowerBound = new BigDecimal(mat.group(2));
ret.upperBound = new BigDecimal(mat.group(4));
ret.upperOpen = mat.group(6).equals(")");
long uom = Long.parseLong(mat.group(7));
ret.unitOfMeasure = new Concept(uom);
return ret;
}
Expand All @@ -112,22 +125,37 @@ public String toString(boolean includeUnitOfMeasure) {
+ (includeUnitOfMeasure ? unitOfMeasure.getId() : "");
}

private int getLowerContainsValue() {
if (this.isLowerOpen())
return this.getLowerBound() + 1;
return this.getLowerBound();
private boolean lowerContains(Interval that) {
if (this.isLowerOpen() && !that.isLowerOpen())
return this.getLowerBound().compareTo(that.getLowerBound()) < 0;
return this.getLowerBound().compareTo(that.getLowerBound()) <= 0;
}

private int getUpperContainsValue() {
if (this.isUpperOpen())
return this.getUpperBound() - 1;
return this.getUpperBound();
private boolean upperContains(Interval that) {
if (this.isUpperOpen() && !that.isUpperOpen())
return this.getUpperBound().compareTo(that.getUpperBound()) > 0;
return this.getUpperBound().compareTo(that.getUpperBound()) >= 0;
}

// an open interval does not include endpoints
// (a, b) = { x | a < x < b }
// a closed interval includes endpoints
// [a, b] = { x | a <= x <= b }

// x contains y
//
// x.LO & y.LO -> x.LB <= y.LB
// x.LC & y.LC -> x.LB <= y.LB
// x.LC & y.LO -> x.LB <= y.LB
// x.LO & y.LC -> x.LB < y.LB
//
// x.UO & y.UO -> x.UB >= y.UB
// x.UC & y.UC -> x.UB >= y.UB
// x.UC & y.UO -> x.UB >= y.UB
// x.UO & y.UC -> x.UB > y.UB

public boolean contains(Interval that) {
return this.getLowerContainsValue() <= that.getLowerContainsValue()
&& this.getUpperContainsValue() >= that.getUpperContainsValue()
&& this.unitOfMeasure.equals(that.unitOfMeasure);
return lowerContains(that) && upperContains(that) && this.unitOfMeasure.equals(that.unitOfMeasure);
}

}
17 changes: 8 additions & 9 deletions elk-snomed/src/main/java/dev/ikm/elk/snomed/model/Concept.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package dev.ikm.elk.snomed.model;

import java.util.List;
import java.util.Objects;

import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.MutableList;

/*-
* #%L
* ELK Integration with SNOMED
Expand All @@ -20,13 +26,6 @@
* #L%
*/

import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.MutableList;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class Concept extends SnomedEntity {

// Use Eclipse Collections adaptive lists
Expand All @@ -39,15 +38,15 @@ public Concept(long id) {
}

public MutableList<Definition> getDefinitions() {
return definitions; // MutableList implements List
return definitions; // MutableList implements List
}

public void addDefinition(Definition definition) {
this.definitions.add(definition);
}

public void removeAllDefinitions() {
this.definitions.clear(); // More efficient than new allocation
this.definitions.clear(); // More efficient than new allocation
}

public List<Definition> getGciDefinitions() {
Expand Down
Loading
Loading