package mhtree; import cz.muni.fi.disa.similarityoperators.cover.AbstractRepresentation.PrecomputedDistances; import cz.muni.fi.disa.similarityoperators.cover.HullOptimizedRepresentationV3; import messif.buckets.BucketStorageException; import messif.objects.LocalAbstractObject; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; public abstract class Node implements Serializable { /** * Serialization ID */ private static final long serialVersionUID = 420L; private final InsertType insertType; private final ObjectToNodeDistance objectToNodeDistance; private HullOptimizedRepresentationV3 hull; protected Node(PrecomputedDistances distances, InsertType insertType, ObjectToNodeDistance objectToNodeDistance) { this.hull = new HullOptimizedRepresentationV3(distances); this.hull.build(); this.insertType = insertType; this.objectToNodeDistance = objectToNodeDistance; } protected static InternalNode createParent(List<Node> nodes, PrecomputedDistances distances, InsertType insertType, ObjectToNodeDistance objectToNodeDistance, MergeType mergeType) { List<LocalAbstractObject> objects = nodes .stream() .map(mergeType == MergeType.OBJECT_BASED ? Node::getObjects : Node::getHullObjects) .flatMap(Collection::stream) .collect(Collectors.toList()); if (nodes.size() == distances.getObjectCount()) { return new InternalNode(distances, insertType, objectToNodeDistance, nodes); } return new InternalNode(distances.getSubset(objects), insertType, objectToNodeDistance, nodes); } /** * Returns a list of hull objects. * * @return a list of hull objects */ public List<LocalAbstractObject> getHullObjects() { return hull.getHull(); } /** * Returns true if the {@code object} is covered. * * @param object the object to be checked * @return true if the {@code object} is covered. */ public boolean isCovered(LocalAbstractObject object) { return hull.isExternalCovered(object); } @Override public String toString() { return "Node{hull=" + hull + '}'; } protected double getDistance(LocalAbstractObject object) { return objectToNodeDistance.getDistance(object, this); } protected double getDistance(LocalAbstractObject object, PrecomputedDistances distances) { return objectToNodeDistance.getDistance(object, this, distances); } protected double getDistanceToNearest(LocalAbstractObject object) { return ObjectToNodeDistance.NEAREST.getDistance(object, this); } protected boolean isLeaf() { return (this instanceof LeafNode); } protected boolean isInternal() { return !isLeaf(); } protected int getHullObjectCount() { return hull.getRepresentativesCount(); } protected void addObjectIntoHull(LocalAbstractObject object) { if (isCovered(object)) return; switch (insertType) { case GREEDY: insertGreedy(object); break; case INCREMENTAL: insertIncremental(object); break; default: throw new IllegalStateException("Unexpected value: " + insertType); } } protected abstract void addObject(LocalAbstractObject object) throws BucketStorageException; protected abstract List<LocalAbstractObject> getObjects(); protected abstract int getHeight(); protected abstract void gatherNodes(List<Node> nodes); protected abstract void gatherLeafNodes(List<LeafNode> leafNodes); private void insertGreedy(LocalAbstractObject object) { List<LocalAbstractObject> objectsFromLeafNodes = getObjects(); objectsFromLeafNodes.add(object); hull = new HullOptimizedRepresentationV3(objectsFromLeafNodes); hull.build(); } private void insertIncremental(LocalAbstractObject object) { List<LocalAbstractObject> hullObjects = hull.getHull(); hullObjects.add(object); hull = new HullOptimizedRepresentationV3(hullObjects); hull.build(); } }