docs: @Override
  	public Map<Long, RandomVariable> getGradient(Set<Long> independentIDs) {
  
  		// The map maintaining the derivatives id -> derivative
  		Map<Long, RandomVariable> derivatives = new HashMap<>();
  		// Put derivative of this node w.r.t. itself
  		derivatives.put(getID(), getFactory().createRandomVariableNonDifferentiable(Double.NEGATIVE_INFINITY, 1.0));
  
  		// The set maintaining the independents. Note: TreeMap is maintaining a sorting on the keys.
  		TreeMap<Long, OperatorTreeNode> independents = new TreeMap<>();
  		// Initialize with root node
  		independents.put(getID(), this.getOperatorTreeNode());
  
  		while(independents.size() > 0) {
  			// Get and remove node with the highest id in independents
  			Map.Entry<Long, OperatorTreeNode> independentEntry = independents.pollLastEntry();
  			Long id = independentEntry.getKey();
  			OperatorTreeNode independent = independentEntry.getValue();
  
  			// Process this node (node with highest id in independents)
  			List<OperatorTreeNode> arguments = independent.arguments;
  			if(arguments != null && arguments.size() > 0) {
  				// Node has arguments: Propagate derivative to arguments.
  				independent.propagateDerivativesFromResultToArgument(derivatives);
  
  				// Remove id of this node from derivatives - keep only leaf nodes.
  				if(isGradientRetainsLeafNodesOnly()) {
  					derivatives.remove(id);
  				}
  
  				// Add all non leaf node arguments to the list of independents
  				for(OperatorTreeNode argument : arguments) {
  					// If an argument is null, it is a (non-differentiable) constant.
  					if(argument != null) {
  						independents.put(argument.id, argument);
  					}
  				}
  			}
  
  			if(independentIDs != null && independentIDs.contains(id)) {
  				derivatives.remove(id);
  			}
  		}
  
  		return derivatives;
  	}