lojix/learning/src/main/com/thesett/aima/learning/decisiontree/prototype/ProtoDTLearningMethod.java
private String chooseBestPropertyToDecideOn(String outputProperty, Iterable<State> examples,
        Iterable<String> inputProperties)
    {
        /*log.fine("private String chooseBestPropertyToDecideOn(String outputProperty, Collection<State> examples, " +
         "Collection<String> inputProperties): called");*/

        // for (State e : examples) /*log.fine(e);*/

        // Determine how many possible values (symbols) the output property can have.
        int numOutputValues =
            examples.iterator().next().getComponentType().getPropertyType(outputProperty).getNumPossibleValues();

        // Used to hold the largest information gain found so far.
        double largestGain = 0.0d;

        // Used to hold the input property that gives the largest gain found so far.
        String largestGainProperty = null;

        // Loop over all the input properties.
        for (String inputProperty : inputProperties)
        {
            // let G = the set of goal property values.
            // let A = the set of property values that the input property can have.

            // Determine how many possible values (symbols) the input property can have.
            int numInputValues =
                examples.iterator().next().getComponentType().getPropertyType(inputProperty).getNumPossibleValues();

            // Create an array to hold the counts of the output symbols.
            int[] outputCounts = new int[numOutputValues];

            // Create arrays to hold the counts of the input symbols and the joint input/output counts.
            int[] inputCounts = new int[numInputValues];
            int[][] jointCounts = new int[numInputValues][numOutputValues];

            // Loop over all the examples.
            for (State example : examples)
            {
                // Extract the output property attribute value.
                OrdinalAttribute outputAttribute = (OrdinalAttribute) example.getProperty(outputProperty);

                // Extract the input property attribute value.
                OrdinalAttribute inputAttribute = (OrdinalAttribute) example.getProperty(inputProperty);

                // Increment the count for the occurence of this value of the output property.
                outputCounts[outputAttribute.ordinal()]++;

                // Increment the count for the occurence of this value of the input property.
                inputCounts[inputAttribute.ordinal()]++;

                // Increment the count for the joint occurrence of this input/output value pair.
                jointCounts[inputAttribute.ordinal()][outputAttribute.ordinal()]++;
            }

            // Calculate the estimated probability distribution of G from the occurrence counts over the examples.
            double[] pForG = InformationTheory.pForDistribution(outputCounts);

            // Calculate the estimated probability distribution of A from the occurrence counts over the examples.
            double[] pForA = InformationTheory.pForDistribution(inputCounts);

            // Calculate the estimated probability distribution p(g|a) from the joint occurrence counts over the
            // examples.
            double[][] pForGGivenA = InformationTheory.pForJointDistribution(jointCounts);

            // Calculate the information gain on G by knowing A.
            double gain = InformationTheory.gain(pForG, pForA, pForGGivenA);

            // Check if the gain is larger than the best found so far and update the best if so.
            if (gain > largestGain)
            {
                largestGain = gain;
                largestGainProperty = inputProperty;
            }
        }

        return largestGainProperty;
    }
private String chooseBestPropertyToDecideOn(String outputProperty, Iterable<State> examples,
        Iterable<String> inputProperties)
    {
        /*log.fine("private String chooseBestPropertyToDecideOn(String outputProperty, Collection<State> examples, " +
         "Collection<String> inputProperties): called");*/

        // for (State e : examples) /*log.fine(e);*/

        // Determine how many possible values (symbols) the output property can have.
        int numOutputValues =
            examples.iterator().next().getComponentType().getPropertyType(outputProperty).getNumPossibleValues();

        // Used to hold the largest information gain found so far.
        double largestGain = 0.0d;

        // Used to hold the input property that gives the largest gain found so far.
        String largestGainProperty = null;

        // Loop over all the input properties.
        for (String inputProperty : inputProperties)
        {
            // let G = the set of goal property values.
            // let A = the set of property values that the input property can have.

            // Determine how many possible values (symbols) the input property can have.
            int numInputValues =
                examples.iterator().next().getComponentType().getPropertyType(inputProperty).getNumPossibleValues();

            // Create an array to hold the counts of the output symbols.
            int[] outputCounts = new int[numOutputValues];

            // Create arrays to hold the counts of the input symbols and the joint input/output counts.
            int[] inputCounts = new int[numInputValues];
            int[][] jointCounts = new int[numInputValues][numOutputValues];

            // Loop over all the examples.
            for (State example : examples)
            {
                // Extract the output property attribute value.
                OrdinalAttribute outputAttribute = (OrdinalAttribute) example.getProperty(outputProperty);

                // Extract the input property attribute value.
                OrdinalAttribute inputAttribute = (OrdinalAttribute) example.getProperty(inputProperty);

                // Increment the count for the occurence of this value of the output property.
                outputCounts[outputAttribute.ordinal()]++;

                // Increment the count for the occurence of this value of the input property.
                inputCounts[inputAttribute.ordinal()]++;

                // Increment the count for the joint occurrence of this input/output value pair.
                jointCounts[inputAttribute.ordinal()][outputAttribute.ordinal()]++;
            }

            // Calculate the estimated probability distribution of G from the occurrence counts over the examples.
            double[] pForG = InformationTheory.pForDistribution(outputCounts);

            // Calculate the estimated probability distribution of A from the occurrence counts over the examples.
            double[] pForA = InformationTheory.pForDistribution(inputCounts);

            // Calculate the estimated probability distribution p(g|a) from the joint occurrence counts over the
            // examples.
            double[][] pForGGivenA = InformationTheory.pForJointDistribution(jointCounts);

            // Calculate the information gain on G by knowing A.
            double gain = InformationTheory.gain(pForG, pForA, pForGGivenA);

            // Check if the gain is larger than the best found so far and update the best if so.
            if (gain > largestGain)
            {
                largestGain = gain;
                largestGainProperty = inputProperty;
            }
        }

        return largestGainProperty;
    }
For a given set of examples, input properties and an output property this method chooses the input property that
provides the largest information gain on the value of the output property.

@param  outputProperty  The name of the property to compare the information gain of the input properties against.
@param  examples        A collection of state objects to count over in order to find the highest information gain
input property.
@param  inputProperties A collection of input properties to find the best one amongst.

@return The name of the input property with the highest information gain.