public static <A> TreeNode<Op<A>> of(
		final int depth,
		final ISeq<? extends Op<A>> operations,
		final ISeq<? extends Op<A>> terminals,
		final RandomGenerator random
	) {
		if (depth < 0) {
			throw new IllegalArgumentException(
				"Tree depth is smaller than zero: " + depth
			);
		}
		if (!operations.forAll(o -> !o.isTerminal())) {
			throw new IllegalArgumentException(
				"Operation list contains terminal op."
			);
		}
		if (!terminals.forAll(Op::isTerminal)) {
			throw new IllegalArgumentException(
				"Terminal list contains non-terminal op."
			);
		}

		final TreeNode<Op<A>> root = TreeNode.of();
		fill(depth, root, operations, terminals, random);
		return root;
	}
Create a new, random program tree from the given (non) terminal
operations with the desired depth. The created program tree is a
<em>full</em> tree.

@since 4.1

@param depth the desired depth of the program tree
@param operations the list of <em>non</em>-terminal operations
@param terminals the list of terminal operations
@param random the random engine used for creating the program
@param <A> the operational type
@return a new program tree
@throws NullPointerException if one of the given operations is
       {@code null}
@throws IllegalArgumentException if the given tree depth is smaller than
        zero
jenetics.prog/src/main/java/io/jenetics/prog/op/Program.java