public static <V> void reindex(final TreeNode<Op<V>> tree) {
		final SortedSet<Var<V>> vars = tree.stream()
			.filter(node -> node.value() instanceof Var)
			.map(node -> (Var<V>)node.value())
			.collect(Collectors.toCollection(TreeSet::new));

		int index = 0;
		final Map<Var<V>, Integer> indexes = new HashMap<>();
		for (Var<V> var : vars) {
			indexes.put(var, index++);
		}

		reindex(tree, indexes);
	}
Re-indexes the variables of the given operation {@code tree}. If the
operation tree is created from its string representation, the indices
of the variables ({@link Var}), are all set to zero, since it needs the
whole tree for setting the indices correctly. The mapping from the node
string to the {@link Op} object, on the other hand, is a <em>local</em>
operation. This method gives you the possibility to fix the indices of
the variables. The indices of the variables are assigned according it's
<em>natural</em> order.

{@snippet lang="java":
final TreeNode<Op<Double>> tree = TreeNode.parse(
    "add(mul(x,y),sub(y,x))",
    MathOp::toMathOp
);

assert Program.eval(tree, 10.0, 5.0) == 100.0; // wrong result
Var.reindex(tree);
assert Program.eval(tree, 10.0, 5.0) == 45.0; // correct result
}
The example above shows a use-case of this method. If you parse a tree
string and convert it to an operation tree, you have to re-index the
variables first. If not, you will get the wrong result when evaluating
the tree. After the re-indexing, you will get the correct result of 45.0.

@since 5.0

@see MathOp#toMathOp(String)
@see Program#eval(Tree, Object[])

@param tree the tree where the variable indices need to be fixed
@param <V> the operation value type
jenetics.prog/src/main/java/io/jenetics/prog/op/Var.java