Passed
Push — master ( e0b928...937cde )
by Julian
03:04 queued 12s
created

computeReachability(Integer,OptMap)   A

Complexity

Conditions 2

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
c 0
b 0
f 0
dl 0
loc 7
rs 10
1
/*
2
 *
3
 * Copyright (C) 2009-2017 Julian Mendez
4
 *
5
 *
6
 * This file is part of jcel.
7
 *
8
 *
9
 * The contents of this file are subject to the GNU Lesser General Public License
10
 * version 3
11
 *
12
 *
13
 * This program is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Lesser General Public License as published by
15
 * the Free Software Foundation, either version 3 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU Lesser General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Lesser General Public License
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 *
27
 * Alternatively, the contents of this file may be used under the terms
28
 * of the Apache License, Version 2.0, in which case the
29
 * provisions of the Apache License, Version 2.0 are applicable instead of those
30
 * above.
31
 *
32
 *
33
 * Licensed under the Apache License, Version 2.0 (the "License");
34
 * you may not use this file except in compliance with the License.
35
 * You may obtain a copy of the License at
36
 *
37
 *     http://www.apache.org/licenses/LICENSE-2.0
38
 *
39
 * Unless required by applicable law or agreed to in writing, software
40
 * distributed under the License is distributed on an "AS IS" BASIS,
41
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42
 * See the License for the specific language governing permissions and
43
 * limitations under the License.
44
 *
45
 */
46
47
package de.tudresden.inf.lat.jcel.core.algorithm.rulebased;
48
49
import java.io.IOException;
50
import java.io.Writer;
51
import java.util.AbstractMap;
52
import java.util.ArrayList;
53
import java.util.Collection;
54
import java.util.Collections;
55
import java.util.HashMap;
56
import java.util.HashSet;
57
import java.util.List;
58
import java.util.Map;
59
import java.util.NoSuchElementException;
60
import java.util.Objects;
61
import java.util.Optional;
62
import java.util.Set;
63
import java.util.logging.Logger;
64
65
import de.tudresden.inf.lat.jcel.core.algorithm.common.Processor;
66
import de.tudresden.inf.lat.jcel.core.algorithm.common.UnclassifiedOntologyException;
67
import de.tudresden.inf.lat.jcel.core.completion.common.REntry;
68
import de.tudresden.inf.lat.jcel.core.completion.common.SEntry;
69
import de.tudresden.inf.lat.jcel.core.graph.IntegerBinaryRelation;
70
import de.tudresden.inf.lat.jcel.core.graph.IntegerHierarchicalGraph;
71
import de.tudresden.inf.lat.jcel.core.graph.IntegerHierarchicalGraphImpl;
72
import de.tudresden.inf.lat.jcel.core.graph.IntegerSubsumerGraph;
73
import de.tudresden.inf.lat.jcel.core.graph.IntegerSubsumerGraphImpl;
74
import de.tudresden.inf.lat.jcel.core.saturation.SubPropertyNormalizer;
75
import de.tudresden.inf.lat.jcel.coreontology.axiom.ExtendedOntology;
76
import de.tudresden.inf.lat.jcel.coreontology.axiom.ExtendedOntologyImpl;
77
import de.tudresden.inf.lat.jcel.coreontology.axiom.NormalizedIntegerAxiom;
78
import de.tudresden.inf.lat.jcel.coreontology.axiom.NormalizedIntegerAxiomFactory;
79
import de.tudresden.inf.lat.jcel.coreontology.datatype.IntegerEntityManager;
80
import de.tudresden.inf.lat.jcel.coreontology.datatype.IntegerEntityType;
81
import de.tudresden.inf.lat.jcel.coreontology.datatype.OntologyExpressivity;
82
import de.tudresden.inf.lat.util.map.OptMap;
83
import de.tudresden.inf.lat.util.map.OptMapImpl;
84
85
/**
86
 * An object of this class is an implementation of a classification algorithm.
87
 * 
88
 * @author Julian Mendez
89
 */
90
public class RuleBasedProcessor implements Processor {
91
92
	private class WorkerThreadR extends Thread {
93
		@Override
94
		public void run() {
95
			while (RuleBasedProcessor.this.status.getNumberOfREntries() > 0) {
96
				while (RuleBasedProcessor.this.status.getNumberOfREntries() > 0) {
97
					processREntries();
98
				}
99
				try {
100
					Thread.sleep(threadWaitingTime);
101
				} catch (InterruptedException e) {
102
					throw new IllegalStateException(e);
103
				}
104
			}
105
		}
106
	}
107
108
	private class WorkerThreadS extends Thread {
109
		@Override
110
		public void run() {
111
			while (RuleBasedProcessor.this.status.getNumberOfSEntries() > 0) {
112
				while (RuleBasedProcessor.this.status.getNumberOfSEntries() > 0) {
113
					processSEntries();
114
				}
115
				try {
116
					Thread.sleep(threadWaitingTime);
117
				} catch (InterruptedException e) {
118
					throw new IllegalStateException(e);
119
				}
120
			}
121
		}
122
	}
123
124
	private static final Logger logger = Logger.getLogger(RuleBasedProcessor.class.getName());
125
126
	private static final long loggingFrequency = 0x1000000;
127
	private static final long threadWaitingTime = 0x20;
128
	private static final Integer topClassId = IntegerEntityManager.topClassId;
129
130
	private RChain chainR = null;
131
	private SChain chainS = null;
132
	private IntegerHierarchicalGraph classHierarchy = null;
133
	private IntegerHierarchicalGraph dataPropertyHierarchy = null;
134
	private OptMap<Integer, Set<Integer>> directTypes = null;
135
	private final IntegerEntityManager entityManager;
136
	private final NormalizedIntegerAxiomFactory factory;
137
	private boolean isReady = false;
138
	private long iteration = 0;
139
	private long loggingCount = loggingFrequency;
140
	private final boolean multiThreadedMode = false;
141
	private IntegerHierarchicalGraph objectPropertyHierarchy = null;
142
	private OptMap<Integer, Set<Integer>> sameIndividualMap = null;
143
	private ClassifierStatusImpl status = null;
144
	private WorkerThreadR threadR1 = null;
145
	private WorkerThreadR threadR2 = null;
146
	private WorkerThreadS threadS1 = null;
147
	private WorkerThreadS threadS2 = null;
148
149
	/**
150
	 * Constructs a new rule-based processor.
151
	 * 
152
	 * @param originalObjectProperties
153
	 *            set of original object properties
154
	 * @param originalClasses
155
	 *            set of original classes
156
	 * @param normalizedAxiomSet
157
	 *            set of normalized axioms
158
	 * @param expressivity
159
	 *            expressivity
160
	 * @param factory
161
	 *            factory of normalized integer axioms
162
	 * @param entityManager
163
	 *            entity manager
164
	 */
165
	public RuleBasedProcessor(Set<Integer> originalObjectProperties, Set<Integer> originalClasses,
166
			Set<NormalizedIntegerAxiom> normalizedAxiomSet, OntologyExpressivity expressivity,
167
			NormalizedIntegerAxiomFactory factory, IntegerEntityManager entityManager) {
168
		Objects.requireNonNull(originalObjectProperties);
169
		Objects.requireNonNull(originalClasses);
170
		Objects.requireNonNull(normalizedAxiomSet);
171
		Objects.requireNonNull(expressivity);
172
		Objects.requireNonNull(factory);
173
		Objects.requireNonNull(entityManager);
174
		this.factory = factory;
175
		this.entityManager = entityManager;
176
177
		CompletionRuleChainSelector selector = new CompletionRuleChainSelector(expressivity);
178
		selector.activateProfiler();
179
		this.chainR = selector.getRChain();
180
		this.chainS = selector.getSChain();
181
182
		preProcess(createExtendedOntology(originalObjectProperties, originalClasses, normalizedAxiomSet));
183
	}
184
185
	public void addAxioms(Set<NormalizedIntegerAxiom> normalizedAxiomSet) {
186
		Objects.requireNonNull(normalizedAxiomSet);
187
		logger.fine("adding axioms ...");
188
		this.status.getExtendedOntology().load(normalizedAxiomSet);
189
		preProcess(this.status.getExtendedOntology());
190
		logger.fine("processor reset.");
191
	}
192
193
	/**
194
	 * @param hierarchicalGraph
195
	 *            graph containing direct subsumers
196
	 * @return a map with all the direct types for each individual.
197
	 */
198
	private OptMap<Integer, Set<Integer>> computeDirectTypes(IntegerHierarchicalGraph hierarchicalGraph) {
199
		OptMap<Integer, Set<Integer>> ret = new OptMapImpl<>(new HashMap<>());
200
		Set<Integer> individuals = getEntityManager().getIndividuals();
201
		individuals.forEach(indiv -> {
202
			Set<Integer> subsumers = hierarchicalGraph.getParents(getEntityManager().getAuxiliaryNominal(indiv).get());
203
			subsumers.forEach(elem -> {
204
				if (getEntityManager().getAuxiliaryNominals().contains(elem)) {
205
					throw new IllegalStateException("An individual has another individual as direct subsumer.");
206
				}
207
			});
208
			ret.put(indiv, Collections.unmodifiableSet(subsumers));
209
		});
210
		return ret;
211
	}
212
213
	/**
214
	 * This is a graph reachability algorithm that returns all elements d
215
	 * reachable from an element c using a path where each segment is from any
216
	 * of the properties in R.
217
	 * 
218
	 * @param c
219
	 *            first element in the path
220
	 * @return the set of all nodes reachable from c using any possible segment
221
	 */
222
	private Set<Integer> computeReachability(Integer c) {
223
		Set<Integer> ret = new HashSet<>();
224
		Set<Integer> toVisit = new HashSet<>();
225
		toVisit.add(c);
226
		while (!toVisit.isEmpty()) {
227
			Integer elem = toVisit.iterator().next();
228
			toVisit.remove(elem);
229
			ret.add(elem);
230
			Set<Integer> newToVisit = new HashSet<>();
231
			this.status.getObjectPropertiesByFirst(elem).forEach(r -> {
232
				IntegerBinaryRelation relation = this.status.getRelationSet().get(r);
233
				newToVisit.addAll(relation.getByFirst(elem));
234
			});
235
			newToVisit.removeAll(ret);
236
			toVisit.addAll(newToVisit);
237
		}
238
		return ret;
239
	}
240
241
	private Set<Integer> computeReachability(Integer c, OptMap<Integer, Set<Integer>> reachableNodeCache) {
242
		Optional<Set<Integer>> optReachableNodes = reachableNodeCache.get(c);
243
		if (!optReachableNodes.isPresent()) {
244
			optReachableNodes = Optional.of(computeReachability(c));
245
			reachableNodeCache.put(c, optReachableNodes.get());
246
		}
247
		return optReachableNodes.get();
248
	}
249
250 View Code Duplication
	private OptMap<Integer, Set<Integer>> computeSameIndividualMap(IntegerHierarchicalGraph hierarchicalGraph) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
251
		OptMap<Integer, Set<Integer>> ret = new OptMapImpl<>(new HashMap<>());
252
		Set<Integer> individuals = getEntityManager().getIndividuals();
253
		individuals.forEach(indiv -> {
254
			Set<Integer> equivalentClasses = hierarchicalGraph
255
					.getEquivalents(getEntityManager().getAuxiliaryNominal(indiv).get());
256
			Set<Integer> equivalents = new HashSet<>();
257
			equivalentClasses.forEach(elem -> {
258
				if (getEntityManager().getAuxiliaryNominals().contains(elem)) {
259
					equivalents.add(getEntityManager().getIndividual(elem).get());
260
				}
261
			});
262
			ret.put(indiv, Collections.unmodifiableSet(equivalents));
263
		});
264
		return ret;
265
	}
266
267
	/**
268
	 * Convenience method to create a map entry. This method returns a map
269
	 * entry.
270
	 * 
271
	 * @param key
272
	 *            key
273
	 * @param value
274
	 *            value
275
	 * @return a map entry created using the parameters
276
	 */
277
	private Map.Entry<String, String> createEntry(String key, String value) {
278
		return new AbstractMap.SimpleEntry<String, String>(key, value);
279
	}
280
281
	private ExtendedOntology createExtendedOntology(Set<Integer> originalObjectPropertySet,
282
			Set<Integer> originalClassSet, Set<NormalizedIntegerAxiom> axioms) {
283
		SubPropertyNormalizer subPropNormalizer = new SubPropertyNormalizer(getOntologyObjectFactory(),
284
				getEntityManager());
285
		Set<NormalizedIntegerAxiom> saturatedNormalizedAxiomSet = subPropNormalizer.apply(axioms);
286
		ExtendedOntology extendedOntology = new ExtendedOntologyImpl();
287
		extendedOntology.load(saturatedNormalizedAxiomSet);
288
		originalObjectPropertySet.forEach(elem -> extendedOntology.addObjectProperty(elem));
289
		originalClassSet.forEach(elem -> extendedOntology.addClass(elem));
290
		return extendedOntology;
291
	}
292
293
	/**
294
	 * Returns the class graph.
295
	 * 
296
	 * @return the class graph.
297
	 */
298
	protected IntegerSubsumerGraph getClassGraph() {
299
		return this.status.getClassGraph();
300
	}
301
302
	@Override
303
	public IntegerHierarchicalGraph getClassHierarchy() {
304
		if (!isReady()) {
305
			throw new UnclassifiedOntologyException();
306
		}
307
		return this.classHierarchy;
308
	}
309
310
	/**
311
	 * Returns information about how the processor configuration.
312
	 * 
313
	 * @return information about how the processor configuration
314
	 */
315
	public List<Map.Entry<String, String>> getConfigurationInfo() {
316
		List<Map.Entry<String, String>> ret = new ArrayList<>();
317
		ret.add(createEntry("processor", getClass().getSimpleName()));
318
		ret.add(createEntry("iterations per log entry", "" + loggingFrequency));
319
		ret.add(createEntry("classes read (including TOP and BOTTOM classes)",
320
				"" + getEntityManager().getEntities(IntegerEntityType.CLASS, false).size()));
321
		ret.add(createEntry("object properties read (including TOP and BOTTOM object properties)",
322
				"" + getEntityManager().getEntities(IntegerEntityType.OBJECT_PROPERTY, false).size()));
323
		ret.add(createEntry("auxiliary classes created (including nominals)",
324
				"" + getEntityManager().getEntities(IntegerEntityType.CLASS, true).size()));
325
		ret.add(createEntry("auxiliary classes created for nominals", "" + getEntityManager().getIndividuals().size()));
326
		ret.add(createEntry("auxiliary object properties created",
327
				"" + getEntityManager().getEntities(IntegerEntityType.OBJECT_PROPERTY, true).size()));
328
		ret.add(createEntry("chain S", this.chainS.toString()));
329
		ret.add(createEntry("chain R", this.chainR.toString()));
330
		return ret;
331
	}
332
333
	@Override
334
	public IntegerHierarchicalGraph getDataPropertyHierarchy() throws UnclassifiedOntologyException {
335
		if (!isReady()) {
336
			throw new UnclassifiedOntologyException();
337
		}
338
		return this.dataPropertyHierarchy;
339
	}
340
341
	/**
342
	 * Computes the descendants using only a hierarchical graph.
343
	 * 
344
	 * @param hierarchicalGraph
345
	 *            a hierarchical graph containing parents and children
346
	 * @param vertex
347
	 *            starting vertex to compute the descendants
348
	 * @return the descendants according the graph
349
	 */
350 View Code Duplication
	private Set<Integer> getDescendants(IntegerHierarchicalGraph hierarchicalGraph, Integer vertex) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
351
		Set<Integer> visited = new HashSet<>();
352
		Set<Integer> queue = new HashSet<>();
353
		queue.add(vertex);
354
		while (!queue.isEmpty()) {
355
			Integer elem = queue.iterator().next();
356
			queue.remove(elem);
357
			visited.add(elem);
358
			Set<Integer> children = new HashSet<>();
359
			children.addAll(hierarchicalGraph.getChildren(elem));
360
			children.removeAll(visited);
361
			queue.addAll(children);
362
		}
363
		return visited;
364
	}
365
366
	@Override
367
	public Map<Integer, Set<Integer>> getDirectTypes() {
368
		if (!isReady()) {
369
			throw new UnclassifiedOntologyException();
370
		}
371
		return Collections.unmodifiableMap(this.directTypes.asMap());
372
	}
373
374
	protected IntegerEntityManager getEntityManager() {
375
		return this.entityManager;
376
	}
377
378
	protected IntegerSubsumerGraph getObjectPropertyGraph() {
379
		return this.status.getObjectPropertyGraph();
380
	}
381
382
	@Override
383
	public IntegerHierarchicalGraph getObjectPropertyHierarchy() {
384
		if (!isReady()) {
385
			throw new UnclassifiedOntologyException();
386
		}
387
		return this.objectPropertyHierarchy;
388
	}
389
390
	/**
391
	 * Returns the ontology object factory.
392
	 * 
393
	 * @return the ontology object factory.
394
	 */
395
	public NormalizedIntegerAxiomFactory getOntologyObjectFactory() {
396
		return this.factory;
397
	}
398
399
	/**
400
	 * Returns the binary relation for a given id, or and empty relation if the
401
	 * id is unknown.
402
	 * 
403
	 * @param relationId
404
	 *            relation id
405
	 * @return the binary relation for the given id, or an empty relation if no
406
	 *         relation is already defined
407
	 */
408
	protected IntegerBinaryRelation getRelation(Integer relationId) {
409
		Objects.requireNonNull(relationId);
410
		return this.status.getRelationSet().get(relationId);
411
	}
412
413
	/**
414
	 * Returns a set containing all relation ids.
415
	 * 
416
	 * @return the set of all relation ids
417
	 */
418
	protected Set<Integer> getRelationIdSet() {
419
		return Collections.unmodifiableSet(this.status.getRelationSet().getElements());
420
	}
421
422
	@Override
423
	public Map<Integer, Set<Integer>> getSameIndividualMap() {
424
		if (!isReady()) {
425
			throw new UnclassifiedOntologyException();
426
		}
427
		return Collections.unmodifiableMap(this.sameIndividualMap.asMap());
428
	}
429
430
	/**
431
	 * Returns information about the processor status.
432
	 * 
433
	 * @return information about the processor status.
434
	 */
435
	public List<Map.Entry<String, String>> getStatusInfo() {
436
		List<Map.Entry<String, String>> ret = new ArrayList<>();
437
		ret.add(createEntry("iteration", "" + this.iteration));
438
		ret.add(createEntry("Q_S", "" + this.status.getNumberOfSEntries()));
439
		ret.add(createEntry("Q_R", "" + this.status.getNumberOfREntries()));
440
		ret.add(createEntry("S", "" + this.status.getDeepSizeOfS()));
441
		ret.add(createEntry("R", "" + this.status.getDeepSizeOfR()));
442
		ret.add(createEntry("V", "" + this.status.getSizeOfV()));
443
		ret.add(createEntry("subV", "" + this.status.getDeepSizeOfV()));
444
		return ret;
445
	}
446
447
	@Override
448
	public boolean isReady() {
449
		return this.isReady;
450
	}
451
452
	/**
453
	 * Post processes the data after the classification phase.
454
	 */
455
	protected void postProcess() {
456
		removeAuxiliaryObjectProperties();
457
		this.objectPropertyHierarchy = new IntegerHierarchicalGraphImpl(getObjectPropertyGraph());
458
459
		removeAuxiliaryClassesExceptNominals();
460
		IntegerHierarchicalGraph hierarchicalGraph = new IntegerHierarchicalGraphImpl(this.status.getClassGraph());
461
		processNominals(hierarchicalGraph);
462
		this.directTypes = computeDirectTypes(hierarchicalGraph);
463
		this.sameIndividualMap = computeSameIndividualMap(hierarchicalGraph);
464
465
		removeAuxiliaryNominals();
466
		this.classHierarchy = new IntegerHierarchicalGraphImpl(this.status.getClassGraph());
467
	};
468
469
	/**
470
	 * The configuration follows the following steps:
471
	 * <ul>
472
	 * <li>creates the property hierarchy</li>
473
	 * <li>prepares all the queues to run the algorithm</li>
474
	 * </ul>
475
	 * 
476
	 * @param ontology
477
	 *            ontology
478
	 */
479
	protected void preProcess(ExtendedOntology ontology) {
480
		logger.fine("configuring processor ...");
481
482
		this.isReady = false;
483
		this.status = new ClassifierStatusImpl(getEntityManager(), ontology);
484
		this.dataPropertyHierarchy = new IntegerHierarchicalGraphImpl(new IntegerSubsumerGraphImpl(
485
				IntegerEntityManager.bottomDataPropertyId, IntegerEntityManager.topDataPropertyId));
486
		Set<Integer> classNameSet = new HashSet<>();
487
		classNameSet.addAll(this.status.getExtendedOntology().getClassSet());
488
		classNameSet.forEach(className -> {
489
			this.status.addNewSEntry(className, className);
490
			this.status.addNewSEntry(className, topClassId);
491
		});
492
493
		logger.fine("processor configured.");
494
		logger.fine(showConfigurationInfo());
495
496
		int numberOfCores = Runtime.getRuntime().availableProcessors();
497
		logger.fine("number of cores : " + numberOfCores);
498
499
		// uncomment the following two lines to allow multithreaded mode
500
		// int suggestedNumberOfThreads = (numberOfCores / 2) - 1;
501
		// this.multiThreadedMode = suggestedNumberOfThreads >= 4;
502
503
		if (this.multiThreadedMode) {
504
			logger.fine("running processor on multiple threads.");
505
		} else {
506
			logger.fine("running processor on a single thread.");
507
		}
508
	}
509
510
	@Override
511
	public boolean process() {
512
		boolean ret = false;
513
		if (this.multiThreadedMode) {
514
			ret = processMultiThreaded();
515
		} else {
516
			ret = processSingleThreaded();
517
		}
518
		if (ret) {
519
			if (this.loggingCount < 1) {
520
				this.loggingCount = loggingFrequency;
521
				logger.fine(showStatusInfo());
522
			}
523
		}
524
		return ret;
525
	};
526
527
	private boolean processMultiThreaded() {
528
		if (!this.isReady) {
529
			if (Objects.nonNull(this.threadS1) && Objects.nonNull(this.threadS2) && Objects.nonNull(this.threadR1)
530
					&& Objects.nonNull(this.threadR2) && this.threadS1.getState().equals(Thread.State.TERMINATED)
531
					&& this.threadS2.getState().equals(Thread.State.TERMINATED)
532
					&& this.threadR1.getState().equals(Thread.State.TERMINATED)
533
					&& this.threadR2.getState().equals(Thread.State.TERMINATED)
534
					&& (this.status.getNumberOfSEntries() == 0) && (this.status.getNumberOfREntries() == 0)) {
535
536
				logger.fine(showStatusInfo());
537
				postProcess();
538
				logger.fine(showConfigurationInfo());
539
				this.isReady = true;
540
			} else {
541
542
				if ((Objects.isNull(this.threadS1)) || (Objects.nonNull(this.threadS1)
543
						&& this.threadS1.getState().equals(Thread.State.TERMINATED))) {
544
					this.threadS1 = new WorkerThreadS();
545
					this.threadS1.start();
546
					logger.finest("starting new thread S-1 ...");
547
				}
548
549
				if ((Objects.isNull(this.threadS2)) || (Objects.nonNull(this.threadS2)
550
						&& this.threadS2.getState().equals(Thread.State.TERMINATED))) {
551
					this.threadS2 = new WorkerThreadS();
552
					this.threadS2.start();
553
					logger.finest("starting new thread S-2 ...");
554
				}
555
556
				if ((Objects.isNull(this.threadR1)) || (Objects.nonNull(this.threadR1)
557
						&& this.threadR1.getState().equals(Thread.State.TERMINATED))) {
558
					this.threadR1 = new WorkerThreadR();
559
					this.threadR1.start();
560
					logger.finest("starting new thread R-1 ...");
561
				}
562
563
				if ((Objects.isNull(this.threadR2)) || (Objects.nonNull(this.threadR2)
564
						&& this.threadR2.getState().equals(Thread.State.TERMINATED))) {
565
					this.threadR2 = new WorkerThreadR();
566
					this.threadR2.start();
567
					logger.finest("starting new thread R-2 ...");
568
				}
569
570
				try {
571
					if (this.status.getNumberOfREntries() < this.status.getNumberOfSEntries()) {
572
						if ((this.iteration % 2) == 0) {
573
							this.threadR1.join();
574
						} else {
575
							this.threadR2.join();
576
						}
577
					} else {
578
						if ((this.iteration % 2) == 0) {
579
							this.threadS1.join();
580
						} else {
581
							this.threadS2.join();
582
						}
583
					}
584
				} catch (InterruptedException e) {
585
					throw new IllegalStateException(e);
586
				}
587
			}
588
		}
589
		return !this.isReady;
590
	}
591
592
	/**
593
	 * Processes the nominals after the execution of the classification
594
	 * algorithm. It requires a hierarchical graph to get the descendants.
595
	 * 
596
	 * @param hierarchicalGraph
597
	 *            the hierarchical graph
598
	 */
599
	private void processNominals(IntegerHierarchicalGraph hierarchicalGraph) {
600
		OptMap<Integer, Set<Integer>> reachabilityCache = new OptMapImpl<>(new HashMap<>());
601
		Set<Integer> nominals = getEntityManager().getAuxiliaryNominals();
602
		nominals.forEach(indiv -> {
603
			Set<Integer> descendants = getDescendants(hierarchicalGraph, indiv);
604
			descendants.forEach(c -> {
605
				descendants.forEach(d -> {
606
					Collection<Integer> sC = getClassGraph().getSubsumers(c);
607
					Collection<Integer> sD = getClassGraph().getSubsumers(d);
608
					if (!(sD.containsAll(sC))) {
609
						if (computeReachability(c, reachabilityCache).contains(d)) {
610
							sD.forEach(elem -> this.status.getClassGraph().addAncestor(c, elem));
611
						}
612
						nominals.forEach(nominal -> {
613
							if (computeReachability(nominal, reachabilityCache).contains(d)) {
614
								sD.forEach(elem -> this.status.getClassGraph().addAncestor(c, elem));
615
							}
616
						});
617
					}
618
				});
619
			});
620
		});
621
	}
622
623
	private boolean processREntries() {
624
		boolean ret = false;
625
		REntry entry = null;
626
		try {
627
			entry = this.status.removeNextREntry();
628
		} catch (NoSuchElementException e) {
629
		}
630
		if (Objects.nonNull(entry)) {
631
			ret = true;
632
			int property = entry.getProperty();
633
			int leftClass = entry.getLeftClass();
634
			int rightClass = entry.getRightClass();
635
			boolean applied = this.status.addToR(property, leftClass, rightClass);
636
			if (applied) {
637
				this.chainR.apply(this.status, property, leftClass, rightClass);
638
				this.loggingCount--;
639
				this.iteration++;
640
			}
641
		}
642
		return ret;
643
	}
644
645
	private boolean processSEntries() {
646
		boolean ret = false;
647
		SEntry entry = null;
648
		try {
649
			entry = this.status.removeNextSEntry();
650
		} catch (NoSuchElementException e) {
651
		}
652
		if (Objects.nonNull(entry)) {
653
			ret = true;
654
			int subClass = entry.getSubClass();
655
			int superClass = entry.getSuperClass();
656
			boolean applied = this.status.addToS(subClass, superClass);
657
			if (applied) {
658
				this.chainS.apply(this.status, subClass, superClass);
659
				this.loggingCount--;
660
				this.iteration++;
661
			}
662
		}
663
		return ret;
664
	}
665
666
	private boolean processSingleThreaded() {
667
		if (!this.isReady) {
668
			if ((this.status.getNumberOfSEntries() == 0) && (this.status.getNumberOfREntries() == 0)) {
669
				logger.fine(showStatusInfo());
670
				postProcess();
671
				logger.fine(showConfigurationInfo());
672
				this.isReady = true;
673
			} else {
674
				if (this.status.getNumberOfSEntries() > this.status.getNumberOfREntries()) {
675
					processSEntries();
676
				} else {
677
					processREntries();
678
				}
679
			}
680
		}
681
		return !this.isReady;
682
	}
683
684
	private void removeAuxiliaryClassesExceptNominals() {
685
		Set<Integer> reqClasses = new HashSet<>();
686
		getClassGraph().getElements().forEach(elem -> {
687
			if (!getEntityManager().isAuxiliary(elem)) {
688
				reqClasses.add(elem);
689
			}
690
		});
691
		reqClasses.addAll(getEntityManager().getAuxiliaryNominals());
692
		this.status.getClassGraph().retainAll(reqClasses);
693
	}
694
695
	private void removeAuxiliaryNominals() {
696
		Set<Integer> reqClasses = new HashSet<>();
697
		reqClasses.addAll(getClassGraph().getElements());
698
		reqClasses.removeAll(getEntityManager().getAuxiliaryNominals());
699
		this.status.getClassGraph().retainAll(reqClasses);
700
	}
701
702
	/**
703
	 * This method removes the auxiliary object properties that were not
704
	 * generated as inverse of another one.
705
	 */
706
	private void removeAuxiliaryObjectProperties() {
707
		Set<Integer> reqObjectProperties = new HashSet<>();
708
		getObjectPropertyGraph().getElements().forEach(elem -> {
709
			if (!getEntityManager().isAuxiliary(elem)) {
710
				reqObjectProperties.add(elem);
711
			}
712
		});
713
		this.status.getObjectPropertyGraph().retainAll(reqObjectProperties);
714
	}
715
716
	public String showConfigurationInfo() {
717
		StringBuffer sbuf = new StringBuffer();
718
		getConfigurationInfo().forEach(entry -> {
719
			sbuf.append(entry.getKey());
720
			sbuf.append(" = ");
721
			sbuf.append(entry.getValue());
722
			sbuf.append("\n");
723
		});
724
		return sbuf.toString();
725
	}
726
727
	public String showStatusInfo() {
728
		StringBuffer sbuf = new StringBuffer();
729
		getStatusInfo().forEach(entry -> {
730
			sbuf.append(entry.getKey());
731
			sbuf.append("=");
732
			sbuf.append(entry.getValue());
733
			sbuf.append(" ");
734
		});
735
		return sbuf.toString();
736
	}
737
738
	public void outputSetS(Writer writer) throws IOException {
739
		this.status.outputSetS(writer);
740
	}
741
742
	public void outputSetR(Writer writer) throws IOException {
743
		this.status.outputSetR(writer);
744
	}
745
746
}
747