private static IDecisionNode NodeToDecisionTree(IDataNode node)
 {
     if (node is DataLeaf)
     {
         DataLeaf leaf   = (DataLeaf)node;
         Tactic   tactic = EnumUtils.GetEnumValues <Tactic>().MaxBy(t => leaf.ClassDistribution[(int)t]);
         return(new DecisionLeaf(tactic));
     }
     else if (node is AttributeSplit)
     {
         AttributeSplit attributeSplit = (AttributeSplit)node;
         return(new DecisionNode {
             Partitioner = new ContinuousPartitioner((ContinuousAxis)attributeSplit.Axis, attributeSplit.SplitValue),
             Left = NodeToDecisionTree(attributeSplit.Left),
             Right = NodeToDecisionTree(attributeSplit.Right),
         });
     }
     else if (node is CategoricalSplit)
     {
         CategoricalSplit categoricalSplit = (CategoricalSplit)node;
         return(new DecisionNode {
             Partitioner = new CategoricalPartitioner(
                 (CategoricalAxis)categoricalSplit.Axis,
                 PolicyHelper.BitsToCategories((CategoricalAxis)categoricalSplit.Axis, categoricalSplit.Categories).ToArray()),
             Left = NodeToDecisionTree(categoricalSplit.Left),
             Right = NodeToDecisionTree(categoricalSplit.Right),
         });
     }
     else
     {
         throw new ArgumentException("Unknown node type: " + node);
     }
 }
 private static DataLeaf Resolve(IDataNode node, DataPoint newDataPoint)
 {
     if (node is DataLeaf)
     {
         return((DataLeaf)node);
     }
     else if (node is AttributeSplit)
     {
         AttributeSplit attributeSplit = (AttributeSplit)node;
         if (newDataPoint.Attributes[attributeSplit.Axis] >= attributeSplit.SplitValue)
         {
             return(Resolve(attributeSplit.Right, newDataPoint));
         }
         else
         {
             return(Resolve(attributeSplit.Left, newDataPoint));
         }
     }
     else if (node is CategoricalSplit)
     {
         CategoricalSplit categoricalSplit = (CategoricalSplit)node;
         if ((newDataPoint.Categories[categoricalSplit.Axis] & categoricalSplit.Categories) != 0)
         {
             return(Resolve(categoricalSplit.Right, newDataPoint));
         }
         else
         {
             return(Resolve(categoricalSplit.Left, newDataPoint));
         }
     }
     else
     {
         throw new ArgumentException("Unknown node type: " + node);
     }
 }
        public void TestSimpleAttributeSplit()
        {
            List <DataPoint> dataPoints = new List <DataPoint> {
                new DataPoint {
                    Class      = 0,
                    Attributes = new float[] { 123 },
                    Categories = new uint[] { },
                    Weight     = 1.0f,
                },
                new DataPoint {
                    Class      = 1,
                    Attributes = new float[] { 456 },
                    Categories = new uint[] { },
                    Weight     = 1.0f,
                },
            };

            using (CudaManager cudaManager = Provider.CudaManagerPool.GetCudaManagerForThread(Provider.Logger))
                using (DecisionLearner decisionLearner = new DecisionLearner(cudaManager, dataPoints)) {
                    IDataNode root = decisionLearner.FitDecisionTree().Node;

                    AttributeSplit attributeSplit = (AttributeSplit)root;
                    Assert.AreEqual(0, attributeSplit.Axis);
                    Assert.AreEqual(456, attributeSplit.SplitValue);

                    DataLeaf left = (DataLeaf)attributeSplit.Left;
                    Assert.AreEqual(1, left.ClassDistribution[0]);
                    Assert.AreEqual(0, left.ClassDistribution[1]);

                    DataLeaf right = (DataLeaf)attributeSplit.Right;
                    Assert.AreEqual(0, right.ClassDistribution[0]);
                    Assert.AreEqual(1, right.ClassDistribution[1]);

                    Assert.AreEqual(1.0, Accuracy(root, dataPoints));
                }
        }
        private DataNodeAccuracy PruneDecisionTree(IDataNode node)
        {
            if (node is DataLeaf)
            {
                return(new DataNodeAccuracy {
                    Node = node,
                    CorrectWeight = node.ClassDistribution.Max(),
                    TotalWeight = node.ClassDistribution.Sum(),
                });
            }
            else if (node is IDataSplit)
            {
                IDataSplit       split         = (IDataSplit)node;
                DataNodeAccuracy leftAccuracy  = PruneDecisionTree(split.Left);
                DataNodeAccuracy rightAccuracy = PruneDecisionTree(split.Right);

                float splitCorrect = leftAccuracy.CorrectWeight + rightAccuracy.CorrectWeight;
                float splitTotal   = leftAccuracy.TotalWeight + rightAccuracy.TotalWeight;

                float leafCorrect = node.ClassDistribution.Max();
                float leafTotal   = node.ClassDistribution.Sum();

#if DEBUGCUDA
                Assert.AreEqual(leafTotal, splitTotal, 1.0f);
#endif

                float accuracyIncrease = splitCorrect - leafCorrect;
                float requiredIncrease = Context.TotalWeight * GPUConstants.RequiredImprovementToSplit;
                if (accuracyIncrease < requiredIncrease)
                {
                    // Split not justified, revert back to leaf at this level
                    return(new DataNodeAccuracy {
                        Node = new DataLeaf {
                            ClassDistribution = node.ClassDistribution
                        },
                        CorrectWeight = leafCorrect,
                        TotalWeight = leafTotal,
                    });
                }
                else
                {
                    // Take the split with the pruned nodes
                    if (split is AttributeSplit)
                    {
                        AttributeSplit attributeSplit = (AttributeSplit)split;
                        attributeSplit.Left  = leftAccuracy.Node;
                        attributeSplit.Right = rightAccuracy.Node;
                    }
                    else if (split is CategoricalSplit)
                    {
                        CategoricalSplit categoricalSplit = (CategoricalSplit)split;
                        categoricalSplit.Left  = leftAccuracy.Node;
                        categoricalSplit.Right = rightAccuracy.Node;
                    }
                    else
                    {
                        throw new ArgumentException("Unknown split type: " + split);
                    }
                    return(new DataNodeAccuracy {
                        Node = split,
                        CorrectWeight = splitCorrect,
                        TotalWeight = splitTotal,
                    });
                }
            }
            else
            {
                throw new ArgumentException("Unknown node type: " + node);
            }
        }