All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kieker.analysis.generic.clustering.mtree.nodes.AbstractNode Maven / Gradle / Ivy

The newest version!
/***************************************************************************
 * Copyright 2022 Kieker Project (http://kieker-monitoring.net)
 *
 * 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 kieker.analysis.generic.clustering.mtree.nodes;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import kieker.analysis.exception.InternalErrorException;
import kieker.analysis.generic.clustering.mtree.DistanceFunctionFactory;
import kieker.analysis.generic.clustering.mtree.IDistanceFunction;
import kieker.analysis.generic.clustering.mtree.ILeafness;
import kieker.analysis.generic.clustering.mtree.IRootness;
import kieker.analysis.generic.clustering.mtree.ISplitFunction.SplitResult;
import kieker.analysis.generic.clustering.mtree.MTree;
import kieker.analysis.generic.clustering.mtree.utils.Pair;

/**
 * @param 
 *            data element type
 *
 * @author Eduardo R. D'Avila
 *
 * @since 2.0.0
 */
public abstract class AbstractNode extends IndexItem {

	protected IRootness rootness;
	protected ILeafness leafness;

	private final Map> children = new HashMap<>();
	private final MTree mtree;

	protected AbstractNode(final MTree mtree, final T data) {
		super(data);

		this.mtree = mtree;
	}

	public Map> getChildren() {
		return this.children;
	}

	public final void addData(final T data, final double distance) throws InternalErrorException {
		this.doAddData(data, distance);
	}

	@Override
	public int check() {
		super.check();
		this.checkMinCapacity();
		this.checkMaxCapacity();

		int childHeight = -1;
		for (final Map.Entry> e : this.children.entrySet()) {
			final T data = e.getKey();
			final IndexItem child = e.getValue();
			assert child.getData().equals(data);

			this.checkChildClass(child);
			this.checkChildMetrics(child);

			final int height = child.check();
			if (childHeight < 0) {
				childHeight = height;
			} else {
				assert childHeight == height;
			}
		}

		return childHeight + 1;
	}

	protected void doAddData(final T data, final double distance) throws InternalErrorException {
		this.leafness.doAddData(data, distance);
	}

	protected boolean doRemoveData(final T data, final double distance) throws InternalErrorException {
		return this.leafness.doRemoveData(data, distance);
	}

	public final boolean isMaxCapacityExceeded() throws InternalErrorException {
		return (this.children.size() > this.mtree.getMaxNodeCapacity());
	}

	public final Pair> splitNodes() throws InternalErrorException {
		final IDistanceFunction cachedDistanceFunction = DistanceFunctionFactory.cached(this.mtree.getDistanceFunction());
		final SplitResult splitResult = this.mtree.getSplitFunction().process(this.children.keySet(), cachedDistanceFunction);

		final AbstractNode newNode0 = this.createNewNode(splitResult, cachedDistanceFunction, 0);
		final AbstractNode newNode1 = this.createNewNode(splitResult, cachedDistanceFunction, 1);

		assert this.children.isEmpty();

		return new Pair<>(newNode0, newNode1);
	}

	private AbstractNode createNewNode(final SplitResult splitResult, final IDistanceFunction distanceFunction, final int resultIndex)
			throws InternalErrorException {
		final T promotedData = splitResult.getPromoted().get(resultIndex);
		final Set partition = splitResult.getPartitions().get(resultIndex);

		final AbstractNode newNode = this.newSplitNodeReplacement(promotedData);
		for (final T data : partition) {
			final IndexItem child = this.children.get(data);
			this.children.remove(data);
			final double distance = distanceFunction.calculate(promotedData, data);
			newNode.addChild(child, distance);
		}

		return newNode;
	}

	protected AbstractNode newSplitNodeReplacement(final T data) {
		return this.leafness.newSplitNodeReplacement(data);
	}

	public void addChild(final IndexItem child, final double distance) throws InternalErrorException {
		this.leafness.addChild(child, distance);
	}

	public boolean removeData(final T data, final double distance)
			throws InternalErrorException {
		return this.doRemoveData(data, distance);
	}

	public boolean isNodeUnderCapacity() throws InternalErrorException {
		return this.children.size() < this.getMinCapacity();
	}

	protected int getMinCapacity() throws InternalErrorException {
		return this.rootness.getMinCapacity();
	}

	public void updateMetrics(final IndexItem child, final double distance) {
		child.setDistanceToParent(distance);
		this.updateRadius(child);
	}

	public void updateRadius(final IndexItem child) {
		this.radius = Math.max(this.radius, child.getDistanceToParent() + child.getRadius());
	}

	public void checkMinCapacity() {
		this.rootness.checkMinCapacity();
	}

	private void checkMaxCapacity() {
		assert this.children.size() <= this.mtree.getMaxNodeCapacity();
	}

	private void checkChildClass(final IndexItem child) {
		this.leafness.checkChildClass(child);
	}

	private void checkChildMetrics(final IndexItem child) {
		final double dist = this.mtree.getDistanceFunction().calculate(child.getData(), this.getData());
		assert child.getDistanceToParent() == dist;

		final double sum = child.getDistanceToParent() + child.getRadius();
		assert sum <= this.radius;
	}

	@Override
	protected void checkDistanceToParent() {
		this.rootness.checkDistanceToParent();
	}

	public MTree getMTree() {
		return this.mtree;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy