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

gov.sandia.cognition.learning.algorithm.tree.AbstractDecisionTreeNode Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                AbstractDecisionTreeNode.java
 * Authors:             Justin Basilico
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 *
 * Copyright November 29, 2007, Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
 * or on behalf of the U.S. Government. Export of this program may require a
 * license from the United States Government. See CopyrightHistory.txt for
 * complete details.
 *
 *
 */

package gov.sandia.cognition.learning.algorithm.tree;

import gov.sandia.cognition.collection.CollectionUtil;
import gov.sandia.cognition.learning.function.categorization.Categorizer;
import gov.sandia.cognition.util.AbstractCloneableSerializable;
import gov.sandia.cognition.util.ObjectUtil;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * The {@code AbstractDecisionTreeNode} class implements common functionality
 * for a decision tree node. It keeps the internal decider plus the collection
 * of child nodes and the incoming label value for the node.
 *
 * @param   The input type of the tree.
 * @param   The output type of the tree.
 * @param   The output of the decision at this node.
 * @author Justin Basilico
 * @since  2.0
 */
public abstract class AbstractDecisionTreeNode
    extends AbstractCloneableSerializable
    implements DecisionTreeNode
{

    /** The parent node of this node. */
    protected DecisionTreeNode parent;
    
    /** The mapping of decider decision values to child nodes. For a leaf node,
     *  this can be null or empty. */
    protected Map
        > 
        childMap;

    /** The decider used to make a decision as to which child use. For a
     *  leaf node, the decider should be null. */
    protected Categorizer decider;

    /** The incoming value for the node. Usually if this is null it means that
     *  the node is a root node. */
    protected Object incomingValue;
    
    /**
     * Creates a new instance of AbstractDecisionTreeNode
     */
    public AbstractDecisionTreeNode()
    {
        this(null, null, null);
    }
    
    /**
     * Creates a new instance of CategorizationTreeNode.
     *
     * @param   parent The parent node of this node.
     * @param   decider The decision function.
     * @param   incomingValue The incoming value.
     */
    public AbstractDecisionTreeNode(
        final DecisionTreeNode parent,
        final Categorizer decider,
        final Object incomingValue)
    {
        super();

        this.setParent(parent);
        this.setDecider(decider);
        this.setChildMap(null);
        this.setIncomingValue(incomingValue);
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public AbstractDecisionTreeNode 
        clone()
    {
        final AbstractDecisionTreeNode result = (AbstractDecisionTreeNode)
            super.clone();
        
        if (this.childMap != null)
        {
            result.childMap = CollectionUtil.createLinkedHashMapWithSize(this.childMap.size());
            for (Map.Entry> entry
                : this.childMap.entrySet())
            {
                final DecisionTreeNode node = (DecisionTreeNode)
                    entry.getValue().clone();
                if (node instanceof AbstractDecisionTreeNode)
                {
                    // Fix the parent pointer.
                    ((AbstractDecisionTreeNode) node).parent = result;
                }
                result.childMap.put(entry.getKey(), node);
            }
        }
        result.decider = ObjectUtil.cloneSmart(this.decider);
        result.incomingValue = ObjectUtil.cloneSmart(this.incomingValue);
        
        return result;
    }
    
    /**
     * Adds a child for a given interior type.
     *
     * @param  value The interior type value for the child.
     * @param  child The child node to add.
     */
    public void addChild(
        final InteriorType value,
        final DecisionTreeNode child)
    {
        if ( this.childMap == null )
        {
            this.childMap = new LinkedHashMap
                >();
        }
        
        this.childMap.put(value, child);
    }
    
    public Collection> getChildren()
    {
        if ( this.isLeaf() )
        {
            return Collections.emptyList();
        }
        else
        {
            return this.childMap.values();
        }
    }

    public boolean isLeaf()
    {
        return this.childMap == null || this.childMap.size() <= 0;
    }

    public DecisionTreeNode chooseChild(
        final InputType input)
    {
        if ( this.isLeaf() || this.decider == null )
        {
            // Leaf nodes have no children.
            return null;
        }
        
        // Apply the decider.
        InteriorType decision = this.decider.evaluate(input);
        if ( decision == null )
        {
            // No decision was made so we can't get a child node.
            return null;
        }
        else
        {
            // Return the child associated with the decision, if one exists.
            return this.childMap.get(decision);
        }
    }

    public int getDepth()
    {
	// A node's depth is the length of the path from the node to
	// the root.  The root node has depth 0.
        return this.parent == null ? 0 : 1 + parent.getDepth();
    }

    public int getTreeSize()
    {
        int size = 1;
        for (DecisionTreeNode child : this.getChildren())
        {
            size += child.getTreeSize();
        }
        return size;
    }

    /**
     * Gets the parent node for this node. Null if it is the root node.
     *
     * @return
     *      The parent node for this node.
     */
    public DecisionTreeNode getParent()
    {
        return this.parent;
    }

    /**
     * Sets the parent node for this node. Null if it is the root node.
     *
     * @param   parent
     *      The parent node for this node.
     */
    public void setParent(
        final DecisionTreeNode parent)
    {
        this.parent = parent;
    }

    /**
     * Gets the decider used at this node.
     *
     * @return The decider used.
     */
    public Categorizer getDecider()
    {
        return this.decider;
    }

    /**
     * Sets the decider used at this node.
     *
     * @param  decider The decider used.
     */
    public void setDecider(
        final Categorizer decider)
    {
        this.decider = decider;
    }

    /**
     * Gets the mapping of decision values to child nodes.
     *
     * @return The child map.
     */
    public Map
        > 
        getChildMap()
    {
        return childMap;
    }

    /**
     * Sets the mapping of decision values to child nodes.
     *
     * @param  childMap The child map.
     */
    protected void setChildMap(
        final Map
            > 
            childMap)
    {
        this.childMap = childMap;
    }
    
    /**
     * {@inheritDoc}
     *
     * @return {@inheritDoc}
     */
    public Object getIncomingValue()
    {
        return this.incomingValue;
    }
    
    /**
     * Sets the incoming value for the node.
     *
     * @param  incomingValue The incoming value for the node.
     */   
    public void setIncomingValue(
        final Object incomingValue)
    {
        this.incomingValue = incomingValue;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy