class Tree {

    public void grow(int buildDirection,
                     double timeStep) {

        SubTree otherHalfTree = buildTree(
            buildDirection == -1 ? backward : forward,
            buildDirection,
            treeHeight,
            timeStep
        );

        if (buildDirection == -1) {
            backward = otherHalfTree.backward;
        } else {
            forward = otherHalfTree.forward;
        }

        sumMetropolisAcceptanceProbability += otherHalfTree.sumMetropolisAcceptanceProbability;
        treeSize += otherHalfTree.treeSize;

        if (otherHalfTree.shouldContinue()) {

            if (Tree.acceptOtherProposalWithProbability(otherHalfTree.getLogSumWeight() - logSumWeight, random)) {
                proposal = otherHalfTree.proposal;
            }

            logSumWeight = logSumExp(logSumWeight, otherHalfTree.logSumWeight);

            sumMomentum = add(sumMomentum, otherHalfTree.sumMomentum);
        }

        diverged = otherHalfTree.diverged;

        if (!diverged) {

            uTurned = otherHalfTree.uTurned || Tree.isUTurning(
                forward.getVelocity(),
                backward.getVelocity(),
                sumMomentum
            );
        }

        treeHeight++;
    }

    public  Tree(LeapfrogState startState,
                Proposal proposal,
                double maxEnergyChange,
                ProbabilisticModelWithGradient logProbGradientCalculator,
                LeapfrogIntegrator leapfrogIntegrator,
                List<? extends Variable> sampleFromVariables,
                KeanuRandom random);

}