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

org.psjava.algo.graph.DistanceCalculatorInRootedTree Maven / Gradle / Ivy

The newest version!
package org.psjava.algo.graph;

import org.psjava.algo.graph.dfs.DFSVisitorBase;
import org.psjava.algo.graph.dfs.SingleSourceDFS;
import org.psjava.ds.array.DynamicArray;
import org.psjava.ds.graph.DirectedWeightedEdge;
import org.psjava.ds.graph.RootedTree;
import org.psjava.ds.map.MutableMap;
import org.psjava.ds.map.MutableMapFactory;
import org.psjava.ds.math.BinaryOperator;
import org.psjava.ds.numbersystrem.AddInvert;
import org.psjava.ds.numbersystrem.AddableNumberSystem;
import org.psjava.ds.tree.segmenttree.SegmentTree;
import org.psjava.ds.tree.segmenttree.SegmentTreeFactory;
import org.psjava.util.VisitorStopper;

// TODO this is not used any problem. solve something to prove this.
public class DistanceCalculatorInRootedTree {

	private final LowestCommonAncestorAlgorithm lca;
	private final SegmentTreeFactory segmentTreeFactory;
	private final MutableMapFactory mapFactory;

	public DistanceCalculatorInRootedTree(LowestCommonAncestorAlgorithm lca, SegmentTreeFactory segmentTreeFactory, MutableMapFactory mapFactory) {
		this.lca = lca;
		this.segmentTreeFactory = segmentTreeFactory;
		this.mapFactory = mapFactory;
	}

	public  DistanceCalculatorInRootedTreeResult calc(RootedTree> tree, final AddableNumberSystem ns) {
		final DynamicArray pathWeights = DynamicArray.create();
		final MutableMap discoverIndex = mapFactory.create();
		final MutableMap indexOfWalkingDown = mapFactory.create();
		final MutableMap indexOfWalkingUp = mapFactory.create();
		SingleSourceDFS.traverse(tree.graph, tree.root, new DFSVisitorBase>() {

			@Override
			public void onDiscovered(V vertex, int depth, VisitorStopper stopper) {
				int index = pathWeights.size();
				discoverIndex.add(vertex, index);
			}

			@Override
			public void onWalkDown(DirectedWeightedEdge outEdge) {
				int index = pathWeights.size();
				indexOfWalkingDown.add(outEdge.to(), index);
				pathWeights.addToLast(outEdge.weight());
			}

			@Override
			public void onWalkUp(DirectedWeightedEdge edge) {
				int index = pathWeights.size();
				indexOfWalkingUp.add(edge.to(), index);
				pathWeights.addToLast(AddInvert.calc(ns, edge.weight()));
			}
		});

		final SegmentTree segmentTree = segmentTreeFactory.create(pathWeights, createAdder(ns));
		final LowestCommonAncestorQuerySession lcaSession = lca.calc(tree);

		return new DistanceCalculatorInRootedTreeResult() {
			@Override
			public W getDistance(V v1, V v2) {
				V ancestor = lcaSession.query(v1, v2);
				W r = ns.getZero();
				if (!v1.equals(ancestor))
					r = ns.add(r, segmentTree.query(discoverIndex.get(ancestor), discoverIndex.get(v1)));
				if (!v2.equals(ancestor))
					r = ns.add(r, segmentTree.query(discoverIndex.get(ancestor), discoverIndex.get(v2)));
				return r;
			}

			@Override
			public void modifyDistance(V v1, V v2, W w) {
				V child = (discoverIndex.get(v1) < discoverIndex.get(v2)) ? v2 : v1;
				segmentTree.update(indexOfWalkingDown.get(child), w);
				segmentTree.update(indexOfWalkingUp.get(child), AddInvert.calc(ns, w));
			}
		};
	}

	private static  BinaryOperator createAdder(final AddableNumberSystem ns) {
		return new BinaryOperator() {
			@Override
			public T calc(T d1, T d2) {
				return ns.add(d1, d2);
			}
		};
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy