| Total Complexity | 76 |
| Total Lines | 636 |
| Duplicated Lines | 4.56 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like de.tudresden.inf.lat.jcel.core.algorithm.cel.CelProcessor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | /* |
||
| 98 | public class CelProcessor implements Processor { |
||
| 99 | |||
| 100 | private static final Integer bottomClassId = IntegerEntityManager.bottomClassId; |
||
| 101 | private static final Integer bottomObjectPropertyId = IntegerEntityManager.bottomObjectPropertyId; |
||
| 102 | private static final Logger logger = Logger.getLogger(CelProcessor.class.getName()); |
||
| 103 | private static final Integer topClassId = IntegerEntityManager.topClassId; |
||
| 104 | private static final Integer topObjectPropertyId = IntegerEntityManager.topObjectPropertyId; |
||
| 105 | |||
| 106 | private final NormalizedIntegerAxiomFactory axiomFactory; |
||
| 107 | private IntegerSubsumerGraphImpl classGraph = null; |
||
| 108 | private IntegerHierarchicalGraph classHierarchy = null; |
||
| 109 | private IntegerHierarchicalGraph dataPropertyHierarchy = null; |
||
| 110 | private Map<Integer, Set<Integer>> directTypes = null; |
||
| 111 | private final IntegerEntityManager entityManager; |
||
| 112 | private CelExtendedOntology extendedOntology = null; |
||
| 113 | private boolean isReady = false; |
||
| 114 | private IntegerSubsumerGraphImpl objectPropertyGraph = null; |
||
| 115 | private IntegerHierarchicalGraph objectPropertyHierarchy = null; |
||
| 116 | private Map<Integer, Set<Integer>> propertyUsedByClass = null; |
||
| 117 | private final Deque<ExtensionEntry> queueEntries = new ArrayDeque<ExtensionEntry>(); |
||
| 118 | private final Deque<Integer> queueKeys = new ArrayDeque<Integer>(); |
||
| 119 | private IntegerRelationMapImpl relationSet = null; |
||
| 120 | private Map<Integer, Set<Integer>> sameIndividualMap = null; |
||
| 121 | private Map<Integer, Set<Integer>> transitiveSubsumed = null; |
||
| 122 | |||
| 123 | /** |
||
| 124 | * Constructs a new CEL processor. |
||
| 125 | * |
||
| 126 | * @param originalObjectProperties |
||
| 127 | * set of object properties |
||
| 128 | * @param originalClasses |
||
| 129 | * set of classes |
||
| 130 | * @param normalizedAxiomSet |
||
| 131 | * set of axioms |
||
| 132 | * @param factory |
||
| 133 | * factory |
||
| 134 | * @param entityManager |
||
| 135 | * entity manager |
||
| 136 | */ |
||
| 137 | public CelProcessor(Set<Integer> originalObjectProperties, Set<Integer> originalClasses, |
||
| 138 | Set<NormalizedIntegerAxiom> normalizedAxiomSet, NormalizedIntegerAxiomFactory factory, |
||
| 139 | IntegerEntityManager entityManager) { |
||
| 140 | Objects.requireNonNull(originalObjectProperties); |
||
| 141 | Objects.requireNonNull(originalClasses); |
||
| 142 | Objects.requireNonNull(normalizedAxiomSet); |
||
| 143 | Objects.requireNonNull(factory); |
||
| 144 | Objects.requireNonNull(entityManager); |
||
| 145 | this.axiomFactory = factory; |
||
| 146 | this.entityManager = entityManager; |
||
| 147 | preProcess(originalObjectProperties, originalClasses, normalizedAxiomSet); |
||
| 148 | } |
||
| 149 | |||
| 150 | private void addToQueue(Integer className, Collection<ExtensionEntry> entrySet) { |
||
| 151 | entrySet.forEach(entry -> { |
||
| 152 | this.queueKeys.push(className); |
||
| 153 | this.queueEntries.push(entry); |
||
| 154 | }); |
||
| 155 | } |
||
| 156 | |||
| 157 | /** |
||
| 158 | * @param hierarchicalGraph |
||
| 159 | * graph containing direct subsumers |
||
| 160 | * @return a map with all the direct types for each individual. |
||
| 161 | */ |
||
| 162 | private Map<Integer, Set<Integer>> computeDirectTypes(IntegerHierarchicalGraph hierarchicalGraph) { |
||
| 163 | Map<Integer, Set<Integer>> ret = new HashMap<>(); |
||
| 164 | Set<Integer> individuals = getEntityManager().getEntities(IntegerEntityType.INDIVIDUAL, false); |
||
| 165 | individuals.forEach(indiv -> { |
||
| 166 | Set<Integer> subsumers = hierarchicalGraph.getParents(getEntityManager().getAuxiliaryNominal(indiv).get()); |
||
| 167 | subsumers.forEach(elem -> { |
||
| 168 | if (getEntityManager().getAuxiliaryNominals().contains(elem)) { |
||
| 169 | throw new IllegalStateException("An individual has another individual as direct subsumer."); |
||
| 170 | } |
||
| 171 | }); |
||
| 172 | ret.put(indiv, Collections.unmodifiableSet(subsumers)); |
||
| 173 | }); |
||
| 174 | return ret; |
||
| 175 | } |
||
| 176 | |||
| 177 | private Map<Integer, Set<Integer>> computeSameIndividualMap(IntegerHierarchicalGraph hierarchicalGraph) { |
||
| 178 | Map<Integer, Set<Integer>> ret = new HashMap<>(); |
||
| 179 | Set<Integer> individuals = getEntityManager().getEntities(IntegerEntityType.INDIVIDUAL, false); |
||
| 180 | individuals.forEach(indiv -> { |
||
| 181 | Set<Integer> equivalentClasses = hierarchicalGraph |
||
| 182 | .getEquivalents(getEntityManager().getAuxiliaryNominal(indiv).get()); |
||
| 183 | Set<Integer> equivalents = new HashSet<>(); |
||
| 184 | equivalentClasses.forEach(elem -> { |
||
| 185 | if (getEntityManager().getAuxiliaryNominals().contains(elem)) { |
||
| 186 | equivalents.add(getEntityManager().getIndividual(elem).get()); |
||
| 187 | } |
||
| 188 | }); |
||
| 189 | ret.put(indiv, Collections.unmodifiableSet(equivalents)); |
||
| 190 | }); |
||
| 191 | return ret; |
||
| 192 | } |
||
| 193 | |||
| 194 | private IntegerSubsumerGraphImpl createClassGraph(Set<Integer> originalClassSet, |
||
| 195 | Set<NormalizedIntegerAxiom> axiomSet) { |
||
| 196 | |||
| 197 | Set<Integer> classIdSet = new HashSet<>(); |
||
| 198 | classIdSet.addAll(originalClassSet); |
||
| 199 | axiomSet.forEach(axiom -> classIdSet.addAll(axiom.getClassesInSignature())); |
||
| 200 | IntegerSubsumerGraphImpl ret = new IntegerSubsumerGraphImpl(bottomClassId, topClassId); |
||
| 201 | classIdSet.forEach(index -> ret.addAncestor(index, topClassId)); |
||
| 202 | ret.addAncestor(topClassId, topClassId); |
||
| 203 | return ret; |
||
| 204 | } |
||
| 205 | |||
| 206 | private IntegerSubsumerGraphImpl createObjectPropertyGraph(Set<Integer> originalPropertySet, |
||
| 207 | Set<NormalizedIntegerAxiom> axiomSet) { |
||
| 208 | IntegerSubsumerGraphImpl ret = new IntegerSubsumerGraphImpl(bottomObjectPropertyId, topObjectPropertyId); |
||
| 209 | Set<Integer> propertyIdSet = new HashSet<>(); |
||
| 210 | propertyIdSet.addAll(originalPropertySet); |
||
| 211 | axiomSet.forEach(axiom -> propertyIdSet.addAll(axiom.getObjectPropertiesInSignature())); |
||
| 212 | propertyIdSet.forEach(index -> ret.addAncestor(index, topObjectPropertyId)); |
||
| 213 | axiomSet.forEach(axiom -> { |
||
| 214 | if (axiom instanceof RI2Axiom) { |
||
| 215 | RI2Axiom current = (RI2Axiom) axiom; |
||
| 216 | ret.addAncestor(current.getSubProperty(), current.getSuperProperty()); |
||
| 217 | } |
||
| 218 | }); |
||
| 219 | makeTransitiveClosure(ret); |
||
| 220 | return ret; |
||
| 221 | } |
||
| 222 | |||
| 223 | private Map<Integer, Set<Integer>> createPropertyUseMap() { |
||
| 224 | Map<Integer, Set<Integer>> ret = new HashMap<>(); |
||
| 225 | getClassGraph().getElements().forEach(cA -> { |
||
| 226 | Set<Integer> propertySet = new HashSet<>(); |
||
| 227 | getObjectPropertyGraph().getElements().forEach(r -> { |
||
| 228 | if (!(this.relationSet.getBySecond(r, cA).isEmpty())) { |
||
| 229 | propertySet.add(r); |
||
| 230 | } |
||
| 231 | }); |
||
| 232 | ret.put(cA, propertySet); |
||
| 233 | }); |
||
| 234 | return ret; |
||
| 235 | } |
||
| 236 | |||
| 237 | private IntegerRelationMapImpl createRelationSet(Collection<Integer> collection) { |
||
| 238 | IntegerRelationMapImpl ret = new IntegerRelationMapImpl(); |
||
| 239 | collection.forEach(index -> ret.add(index)); |
||
| 240 | return ret; |
||
| 241 | } |
||
| 242 | |||
| 243 | private Map<Integer, Set<Integer>> createTransitiveSubsumed() { |
||
| 244 | Map<Integer, Set<Integer>> ret = new HashMap<>(); |
||
| 245 | getObjectPropertyGraph().getElements().forEach(r -> { |
||
| 246 | Set<Integer> related = new HashSet<>(); |
||
| 247 | getObjectPropertyGraph().getElements().forEach(s -> { |
||
| 248 | if (isReflexiveTransitiveSubsumed(r, s)) { |
||
| 249 | related.add(s); |
||
| 250 | } |
||
| 251 | }); |
||
| 252 | ret.put(r, related); |
||
| 253 | }); |
||
| 254 | return ret; |
||
| 255 | } |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Returns the class graph. |
||
| 259 | * |
||
| 260 | * @return the class graph. |
||
| 261 | */ |
||
| 262 | protected IntegerSubsumerGraph getClassGraph() { |
||
| 263 | return this.classGraph; |
||
| 264 | } |
||
| 265 | |||
| 266 | @Override |
||
| 267 | public IntegerHierarchicalGraph getClassHierarchy() { |
||
| 268 | if (!isReady()) { |
||
| 269 | throw new UnclassifiedOntologyException(); |
||
| 270 | } |
||
| 271 | return this.classHierarchy; |
||
| 272 | } |
||
| 273 | |||
| 274 | @Override |
||
| 275 | public IntegerHierarchicalGraph getDataPropertyHierarchy() throws UnclassifiedOntologyException { |
||
| 276 | if (!isReady()) { |
||
| 277 | throw new UnclassifiedOntologyException(); |
||
| 278 | } |
||
| 279 | return this.dataPropertyHierarchy; |
||
| 280 | } |
||
| 281 | |||
| 282 | /** |
||
| 283 | * Computes the descendants using only a hierarchical graph. |
||
| 284 | * |
||
| 285 | * @param hierarchicalGraph |
||
| 286 | * a hierarchical graph containing parents and children |
||
| 287 | * @param vertex |
||
| 288 | * starting vertex to compute the descendants |
||
| 289 | * @return the descendants according the graph |
||
| 290 | */ |
||
| 291 | View Code Duplication | private Set<Integer> getDescendants(IntegerHierarchicalGraph hierarchicalGraph, Integer vertex) { |
|
|
|
|||
| 292 | Set<Integer> visited = new HashSet<>(); |
||
| 293 | Set<Integer> queue = new HashSet<>(); |
||
| 294 | queue.add(vertex); |
||
| 295 | while (!queue.isEmpty()) { |
||
| 296 | Integer elem = queue.iterator().next(); |
||
| 297 | queue.remove(elem); |
||
| 298 | visited.add(elem); |
||
| 299 | Set<Integer> children = new HashSet<>(); |
||
| 300 | children.addAll(hierarchicalGraph.getChildren(elem)); |
||
| 301 | children.removeAll(visited); |
||
| 302 | queue.addAll(children); |
||
| 303 | } |
||
| 304 | return visited; |
||
| 305 | } |
||
| 306 | |||
| 307 | @Override |
||
| 308 | public Map<Integer, Set<Integer>> getDirectTypes() { |
||
| 309 | if (!isReady()) { |
||
| 310 | throw new UnclassifiedOntologyException(); |
||
| 311 | } |
||
| 312 | return Collections.unmodifiableMap(this.directTypes); |
||
| 313 | } |
||
| 314 | |||
| 315 | /** |
||
| 316 | * Returns the id generator. |
||
| 317 | * |
||
| 318 | * @return the id generator. |
||
| 319 | */ |
||
| 320 | protected IntegerEntityManager getEntityManager() { |
||
| 321 | return this.entityManager; |
||
| 322 | } |
||
| 323 | |||
| 324 | protected CelExtendedOntology getExtendedOntology() { |
||
| 325 | return this.extendedOntology; |
||
| 326 | } |
||
| 327 | |||
| 328 | protected IntegerSubsumerGraph getObjectPropertyGraph() { |
||
| 329 | return this.objectPropertyGraph; |
||
| 330 | } |
||
| 331 | |||
| 332 | @Override |
||
| 333 | public IntegerHierarchicalGraph getObjectPropertyHierarchy() { |
||
| 334 | if (!isReady()) { |
||
| 335 | throw new UnclassifiedOntologyException(); |
||
| 336 | } |
||
| 337 | return this.objectPropertyHierarchy; |
||
| 338 | } |
||
| 339 | |||
| 340 | public NormalizedIntegerAxiomFactory getOntologyObjectFactory() { |
||
| 341 | return this.axiomFactory; |
||
| 342 | } |
||
| 343 | |||
| 344 | private Set<Integer> getPropertyUsedByClass(Integer cA) { |
||
| 345 | return this.propertyUsedByClass.get(cA); |
||
| 346 | } |
||
| 347 | |||
| 348 | /** |
||
| 349 | * Returns the binary relation for a given id, or and empty relation if the |
||
| 350 | * id is unknown. |
||
| 351 | * |
||
| 352 | * @param relationId |
||
| 353 | * relation id |
||
| 354 | * @return the binary relation for the given id, or an empty relation if no |
||
| 355 | * relation is already defined |
||
| 356 | */ |
||
| 357 | protected IntegerBinaryRelation getRelation(Integer relationId) { |
||
| 358 | Objects.requireNonNull(relationId); |
||
| 359 | return this.relationSet.get(relationId); |
||
| 360 | } |
||
| 361 | |||
| 362 | /** |
||
| 363 | * Returns a set containing all relation ids. |
||
| 364 | * |
||
| 365 | * @return the set of all relation ids |
||
| 366 | */ |
||
| 367 | protected Set<Integer> getRelationIdSet() { |
||
| 368 | return Collections.unmodifiableSet(this.relationSet.getElements()); |
||
| 369 | } |
||
| 370 | |||
| 371 | @Override |
||
| 372 | public Map<Integer, Set<Integer>> getSameIndividualMap() { |
||
| 373 | if (!isReady()) { |
||
| 374 | throw new UnclassifiedOntologyException(); |
||
| 375 | } |
||
| 376 | return Collections.unmodifiableMap(this.sameIndividualMap); |
||
| 377 | } |
||
| 378 | |||
| 379 | /** |
||
| 380 | * This is a graph reachability algorithm that tests whether an element d is |
||
| 381 | * reachable from an element c using a path where each segment is from any |
||
| 382 | * of the properties in R. |
||
| 383 | * |
||
| 384 | * @param c |
||
| 385 | * first element in the path |
||
| 386 | * @param d |
||
| 387 | * last element in the path |
||
| 388 | * @return <code>true</code> if it is possible to reach d from c using any |
||
| 389 | * possible segment, <code>false</code> otherwise |
||
| 390 | */ |
||
| 391 | private boolean isConnectedTo(Integer c, Integer d) { |
||
| 392 | Set<Integer> visited = new HashSet<>(); |
||
| 393 | Set<Integer> toVisit = new HashSet<>(); |
||
| 394 | toVisit.add(c); |
||
| 395 | while (!toVisit.isEmpty()) { |
||
| 396 | Integer elem = toVisit.iterator().next(); |
||
| 397 | toVisit.remove(elem); |
||
| 398 | visited.add(elem); |
||
| 399 | Set<Integer> newToVisit = new HashSet<>(); |
||
| 400 | getPropertyUsedByClass(elem).forEach(r -> { |
||
| 401 | IntegerBinaryRelation relation = this.relationSet.get(r); |
||
| 402 | newToVisit.addAll(relation.getByFirst(elem)); |
||
| 403 | }); |
||
| 404 | newToVisit.removeAll(visited); |
||
| 405 | toVisit.addAll(newToVisit); |
||
| 406 | } |
||
| 407 | return visited.contains(d); |
||
| 408 | } |
||
| 409 | |||
| 410 | @Override |
||
| 411 | public boolean isReady() { |
||
| 412 | return this.isReady; |
||
| 413 | } |
||
| 414 | |||
| 415 | private boolean isReflexiveTransitiveSubsumed(Integer leftPropertyName, Integer rightPropertyName) { |
||
| 416 | return Objects.nonNull(this.objectPropertyGraph) |
||
| 417 | && this.objectPropertyGraph.containsPair(leftPropertyName, rightPropertyName); |
||
| 418 | } |
||
| 419 | |||
| 420 | private void makeTransitiveClosure(IntegerSubsumerGraphImpl graph) { |
||
| 421 | boolean hasChanged = true; |
||
| 422 | while (hasChanged) { |
||
| 423 | hasChanged = false; |
||
| 424 | for (Integer elem : graph.getElements()) { |
||
| 425 | Collection<Integer> subsumerSet = graph.getSubsumers(elem); |
||
| 426 | Set<Integer> allSubsumers = new HashSet<>(); |
||
| 427 | allSubsumers.add(elem); |
||
| 428 | for (Integer otherElem : subsumerSet) { |
||
| 429 | allSubsumers.addAll(graph.getSubsumers(otherElem)); |
||
| 430 | } |
||
| 431 | allSubsumers.removeAll(subsumerSet); |
||
| 432 | if (!allSubsumers.isEmpty()) { |
||
| 433 | hasChanged = true; |
||
| 434 | for (Integer subsumer : allSubsumers) { |
||
| 435 | graph.addAncestor(elem, subsumer); |
||
| 436 | } |
||
| 437 | } |
||
| 438 | } |
||
| 439 | } |
||
| 440 | } |
||
| 441 | |||
| 442 | /** |
||
| 443 | * Post processes the data after the classification phase. |
||
| 444 | */ |
||
| 445 | protected void postProcess() { |
||
| 446 | removeAuxiliaryObjectProperties(); |
||
| 447 | this.objectPropertyHierarchy = new IntegerHierarchicalGraphImpl(this.objectPropertyGraph); |
||
| 448 | this.objectPropertyGraph = null; |
||
| 449 | |||
| 450 | removeAuxiliaryClassesExceptNominals(); |
||
| 451 | IntegerHierarchicalGraph hierarchicalGraph = new IntegerHierarchicalGraphImpl(this.classGraph); |
||
| 452 | processNominals(hierarchicalGraph); |
||
| 453 | this.directTypes = computeDirectTypes(hierarchicalGraph); |
||
| 454 | this.sameIndividualMap = computeSameIndividualMap(hierarchicalGraph); |
||
| 455 | |||
| 456 | removeAuxiliaryNominals(); |
||
| 457 | this.classHierarchy = new IntegerHierarchicalGraphImpl(this.classGraph); |
||
| 458 | this.classGraph = null; |
||
| 459 | } |
||
| 460 | |||
| 461 | private void prepareQueue(CelExtendedOntology ontology) { |
||
| 462 | Set<Integer> classNameSet = new HashSet<>(); |
||
| 463 | classNameSet.addAll(ontology.getClassSet()); |
||
| 464 | classNameSet.forEach(className -> { |
||
| 465 | addToQueue(className, ontology.getClassEntries(className)); |
||
| 466 | addToQueue(className, ontology.getClassEntries(topClassId)); |
||
| 467 | }); |
||
| 468 | } |
||
| 469 | |||
| 470 | /** |
||
| 471 | * The configuration follows the following steps: |
||
| 472 | * <ul> |
||
| 473 | * <li>normalizes the ontology creating auxiliary entities</li> |
||
| 474 | * <li>creates an extended ontonlogy based on the normalized ontology</li> |
||
| 475 | * <li>adds the classes</li> |
||
| 476 | * <li>creates the property hierarchy</li> |
||
| 477 | * <li>prepares all the queues to run the algorithm</li> |
||
| 478 | * </ul> |
||
| 479 | * |
||
| 480 | * @param originalObjectProperties |
||
| 481 | * set of object properties |
||
| 482 | * @param originalClasses |
||
| 483 | * set of classes |
||
| 484 | * @param normalizedAxiomSet |
||
| 485 | * set of axioms, i.e. the ontology |
||
| 486 | * |
||
| 487 | */ |
||
| 488 | protected void preProcess(Set<Integer> originalObjectProperties, Set<Integer> originalClasses, |
||
| 489 | Set<NormalizedIntegerAxiom> normalizedAxiomSet) { |
||
| 490 | Objects.requireNonNull(originalObjectProperties); |
||
| 491 | Objects.requireNonNull(originalClasses); |
||
| 492 | Objects.requireNonNull(normalizedAxiomSet); |
||
| 493 | this.isReady = false; |
||
| 494 | |||
| 495 | logger.fine("using " + getClass().getSimpleName() + " ..."); |
||
| 496 | |||
| 497 | logger.fine("configuring processor ..."); |
||
| 498 | |||
| 499 | this.dataPropertyHierarchy = new IntegerHierarchicalGraphImpl(new IntegerSubsumerGraphImpl( |
||
| 500 | IntegerEntityManager.bottomDataPropertyId, IntegerEntityManager.topDataPropertyId)); |
||
| 501 | |||
| 502 | // These sets include the declared entities that are not present in the |
||
| 503 | // normalized axioms. |
||
| 504 | Set<Integer> originalClassSet = new HashSet<>(); |
||
| 505 | originalClassSet.addAll(originalClasses); |
||
| 506 | originalClassSet.add(bottomClassId); |
||
| 507 | originalClassSet.add(topClassId); |
||
| 508 | |||
| 509 | Set<Integer> originalObjectPropertySet = new HashSet<>(); |
||
| 510 | originalObjectPropertySet.addAll(originalObjectProperties); |
||
| 511 | originalObjectPropertySet.add(bottomObjectPropertyId); |
||
| 512 | originalObjectPropertySet.add(topObjectPropertyId); |
||
| 513 | |||
| 514 | logger.finer("normalizing ontology ..."); |
||
| 515 | Set<NormalizedIntegerAxiom> ontology = new HashSet<>(); |
||
| 516 | ontology.addAll(normalizedAxiomSet); |
||
| 517 | |||
| 518 | logger.finer("auxiliary classes created (including nominals) : " |
||
| 519 | + getEntityManager().getEntities(IntegerEntityType.CLASS, true).size()); |
||
| 520 | logger.finer("auxiliary classes created for nominals : " + (getEntityManager().getIndividuals().size())); |
||
| 521 | logger.finer("auxiliary object properties created : " |
||
| 522 | + getEntityManager().getEntities(IntegerEntityType.OBJECT_PROPERTY, true).size()); |
||
| 523 | |||
| 524 | logger.finer("creating extended ontology ..."); |
||
| 525 | this.extendedOntology = new CelExtendedOntology(); |
||
| 526 | this.extendedOntology.load(ontology); |
||
| 527 | |||
| 528 | logger.finer("creating class graph ..."); |
||
| 529 | this.classGraph = createClassGraph(originalClassSet, ontology); |
||
| 530 | |||
| 531 | logger.finer("creating property graph ..."); |
||
| 532 | this.objectPropertyGraph = createObjectPropertyGraph(originalObjectPropertySet, ontology); |
||
| 533 | |||
| 534 | this.relationSet = createRelationSet(this.objectPropertyGraph.getElements()); |
||
| 535 | |||
| 536 | this.propertyUsedByClass = createPropertyUseMap(); |
||
| 537 | |||
| 538 | this.transitiveSubsumed = createTransitiveSubsumed(); |
||
| 539 | |||
| 540 | logger.finer("preparing queue ..."); |
||
| 541 | this.queueKeys.clear(); |
||
| 542 | this.queueEntries.clear(); |
||
| 543 | prepareQueue(this.extendedOntology); |
||
| 544 | |||
| 545 | logger.fine("processor configured."); |
||
| 546 | } |
||
| 547 | |||
| 548 | @Override |
||
| 549 | public boolean process() { |
||
| 550 | if (!this.isReady) { |
||
| 551 | if (!this.queueKeys.isEmpty()) { |
||
| 552 | process(this.queueKeys.pop(), this.queueEntries.pop()); |
||
| 553 | } else if (!this.isReady) { |
||
| 554 | postProcess(); |
||
| 555 | this.isReady = true; |
||
| 556 | } |
||
| 557 | } |
||
| 558 | return !this.isReady; |
||
| 559 | } |
||
| 560 | |||
| 561 | private void process(Integer cA, ExtensionEntry eX) { |
||
| 562 | if (eX.isImplication()) { |
||
| 563 | processImplication(cA, eX.asImplication().get()); |
||
| 564 | } else if (eX.isExistential()) { |
||
| 565 | processExistential(cA, eX.asExistential().get()); |
||
| 566 | } else { |
||
| 567 | throw new RuntimeException("Internal error: entry was not recognized " + eX); |
||
| 568 | } |
||
| 569 | } |
||
| 570 | |||
| 571 | private void processBottom(Integer className) { |
||
| 572 | this.classGraph.addAncestor(className, bottomClassId); |
||
| 573 | |||
| 574 | this.relationSet.getElements().forEach(relation -> { |
||
| 575 | this.relationSet.getBySecond(relation, className).forEach(firstComponent -> { |
||
| 576 | if (!this.classGraph.containsPair(firstComponent, bottomClassId)) { |
||
| 577 | processBottom(firstComponent); |
||
| 578 | } |
||
| 579 | }); |
||
| 580 | }); |
||
| 581 | } |
||
| 582 | |||
| 583 | private void processExistential(Integer cA, ExistentialEntry eX) { |
||
| 584 | Integer r = eX.getPropertyId(); |
||
| 585 | Integer cB = eX.getClassId(); |
||
| 586 | Integer bottom = bottomClassId; |
||
| 587 | |||
| 588 | if (!this.relationSet.contains(r, cA, cB)) { |
||
| 589 | |||
| 590 | if (this.classGraph.containsPair(cB, bottom) && !this.classGraph.containsPair(cA, bottom)) { |
||
| 591 | |||
| 592 | processBottom(cA); |
||
| 593 | |||
| 594 | } |
||
| 595 | |||
| 596 | processNewEdge(cA, r, cB); |
||
| 597 | } |
||
| 598 | } |
||
| 599 | |||
| 600 | private void processImplication(Integer cA, ImplicationEntry eX) { |
||
| 601 | Set<Integer> vecB = eX.getOperands(); |
||
| 602 | Integer cB = eX.getSuperClass(); |
||
| 603 | Collection<Integer> sSofA = this.classGraph.getSubsumers(cA); |
||
| 604 | Integer bottom = bottomClassId; |
||
| 605 | |||
| 606 | if (sSofA.containsAll(vecB) && !sSofA.contains(cB)) { |
||
| 607 | |||
| 608 | if (cB.equals(bottom)) { |
||
| 609 | |||
| 610 | processBottom(cA); |
||
| 611 | |||
| 612 | } else { |
||
| 613 | |||
| 614 | this.classGraph.addAncestor(cA, cB); |
||
| 615 | |||
| 616 | addToQueue(cA, getExtendedOntology().getClassEntries(cB)); |
||
| 617 | |||
| 618 | Set<Integer> propertySet = getPropertyUsedByClass(cA); |
||
| 619 | |||
| 620 | propertySet.forEach(r -> { |
||
| 621 | |||
| 622 | Set<ExtensionEntry> existentialEntries = getExtendedOntology().getExistentialEntries(r, cB); |
||
| 623 | |||
| 624 | Collection<Integer> classSet = this.relationSet.getBySecond(r, cA); |
||
| 625 | |||
| 626 | classSet.forEach(cAprime -> addToQueue(cAprime, existentialEntries)); |
||
| 627 | |||
| 628 | }); |
||
| 629 | } |
||
| 630 | } |
||
| 631 | } |
||
| 632 | |||
| 633 | private void processNewEdge(Integer cA, Integer r, Integer cB) { |
||
| 634 | this.transitiveSubsumed.get(r).forEach(s -> { |
||
| 635 | |||
| 636 | this.relationSet.add(s, cA, cB); |
||
| 637 | getPropertyUsedByClass(cB).add(s); |
||
| 638 | |||
| 639 | this.classGraph.getSubsumers(cB) |
||
| 640 | .forEach(cBprime -> addToQueue(cA, getExtendedOntology().getExistentialEntries(s, cBprime))); |
||
| 641 | |||
| 642 | getExtendedOntology().getSubPropertyAxiomSetByRight(s).forEach(axiom -> { |
||
| 643 | |||
| 644 | Integer t = axiom.getLeftSubProperty(); |
||
| 645 | Integer u = axiom.getSuperProperty(); |
||
| 646 | |||
| 647 | Collection<Integer> classSet = this.relationSet.getBySecond(t, cA); |
||
| 648 | |||
| 649 | classSet.forEach(cAprime -> { |
||
| 650 | |||
| 651 | if (!this.relationSet.contains(u, cAprime, cB)) { |
||
| 652 | processNewEdge(cAprime, u, cB); |
||
| 653 | } |
||
| 654 | |||
| 655 | }); |
||
| 656 | |||
| 657 | }); |
||
| 658 | |||
| 659 | getExtendedOntology().getSubPropertyAxiomSetByLeft(s).forEach(axiom -> { |
||
| 660 | |||
| 661 | Integer t = axiom.getRightSubProperty(); |
||
| 662 | Integer u = axiom.getSuperProperty(); |
||
| 663 | |||
| 664 | Collection<Integer> classSet = this.relationSet.getByFirst(t, cB); |
||
| 665 | |||
| 666 | classSet.forEach(cBprime -> { |
||
| 667 | |||
| 668 | if (!this.relationSet.contains(u, cA, cBprime)) { |
||
| 669 | processNewEdge(cA, u, cBprime); |
||
| 670 | } |
||
| 671 | |||
| 672 | }); |
||
| 673 | |||
| 674 | }); |
||
| 675 | }); |
||
| 676 | } |
||
| 677 | |||
| 678 | /** |
||
| 679 | * Processes the nominals after the execution of the classification |
||
| 680 | * algorithm. It requires a hierarchical graph to get the descendants. |
||
| 681 | * |
||
| 682 | * @param hierarchicalGraph |
||
| 683 | * the hierarchical graph |
||
| 684 | */ |
||
| 685 | View Code Duplication | private void processNominals(IntegerHierarchicalGraph hierarchicalGraph) { |
|
| 686 | Set<Integer> nominals = getEntityManager().getAuxiliaryNominals(); |
||
| 687 | nominals.forEach(indiv -> { |
||
| 688 | Set<Integer> descendants = getDescendants(hierarchicalGraph, indiv); |
||
| 689 | descendants.forEach(c -> { |
||
| 690 | descendants.forEach(d -> { |
||
| 691 | Collection<Integer> sC = getClassGraph().getSubsumers(c); |
||
| 692 | Collection<Integer> sD = getClassGraph().getSubsumers(d); |
||
| 693 | if (!(sD.containsAll(sC))) { |
||
| 694 | if (isConnectedTo(c, d)) { |
||
| 695 | sD.forEach(elem -> this.classGraph.addAncestor(c, elem)); |
||
| 696 | } |
||
| 697 | nominals.forEach(nominal -> { |
||
| 698 | if (isConnectedTo(nominal, d)) { |
||
| 699 | sD.forEach(elem -> this.classGraph.addAncestor(c, elem)); |
||
| 700 | } |
||
| 701 | }); |
||
| 702 | } |
||
| 703 | }); |
||
| 704 | }); |
||
| 705 | }); |
||
| 706 | } |
||
| 707 | |||
| 708 | private void removeAuxiliaryClassesExceptNominals() { |
||
| 709 | Set<Integer> reqClasses = new HashSet<>(); |
||
| 710 | getClassGraph().getElements().forEach(elem -> { |
||
| 711 | if (!getEntityManager().isAuxiliary(elem)) { |
||
| 712 | reqClasses.add(elem); |
||
| 713 | } |
||
| 714 | }); |
||
| 715 | reqClasses.addAll(getEntityManager().getAuxiliaryNominals()); |
||
| 716 | this.classGraph.retainAll(reqClasses); |
||
| 717 | } |
||
| 718 | |||
| 719 | private void removeAuxiliaryNominals() { |
||
| 720 | Set<Integer> reqClasses = new HashSet<>(); |
||
| 721 | reqClasses.addAll(getClassGraph().getElements()); |
||
| 722 | reqClasses.removeAll(getEntityManager().getAuxiliaryNominals()); |
||
| 723 | this.classGraph.retainAll(reqClasses); |
||
| 724 | } |
||
| 725 | |||
| 726 | private void removeAuxiliaryObjectProperties() { |
||
| 727 | Set<Integer> reqObjectProperties = new HashSet<>(); |
||
| 728 | getObjectPropertyGraph().getElements().forEach(elem -> { |
||
| 729 | if (!getEntityManager().isAuxiliary(elem)) { |
||
| 730 | reqObjectProperties.add(elem); |
||
| 731 | } |
||
| 732 | }); |
||
| 733 | this.objectPropertyGraph.retainAll(reqObjectProperties); |
||
| 734 | } |
||
| 737 |