private void AppendLeaves(GPUNode[] gpuNodes, int nodeIndex, List <GPUNode> leaves)
        {
            GPUNode node = gpuNodes[nodeIndex];

            switch (node.SplitType)
            {
            case GPUConstants.SplitType_Null:
                throw new InvalidOperationException("Null node in tree");

            case GPUConstants.SplitType_None:
                leaves.Add(node);
                break;

            case GPUConstants.SplitType_Attribute:
            case GPUConstants.SplitType_Categorical:
                AppendLeaves(gpuNodes, node.LeftChild, leaves);
                AppendLeaves(gpuNodes, node.RightChild, leaves);
                break;

            default:
                throw new InvalidOperationException("Unknown split type: " + node.SplitType);
            }
        }
        private IDataNode ReadDecisionTree(GPUNode[] nodes, int nodeIndex)
        {
            GPUNode node = nodes[nodeIndex];

            switch (node.SplitType)
            {
            case GPUConstants.SplitType_Null:
                throw new InvalidOperationException("Null node in tree");

            case GPUConstants.SplitType_None:
                return(new DataLeaf {
                    ClassDistribution = ReadClassDistribution(node.ClassDistribution),
                });

            case GPUConstants.SplitType_Attribute:
                return(new AttributeSplit {
                    Axis = node.SplitAxis,
                    SplitValue = node.SplitAttribute,
                    Left = ReadDecisionTree(nodes, node.LeftChild),
                    Right = ReadDecisionTree(nodes, node.RightChild),
                    ClassDistribution = ReadClassDistribution(node.ClassDistribution),
                });

            case GPUConstants.SplitType_Categorical:
                return(new CategoricalSplit {
                    Axis = node.SplitAxis,
                    Categories = node.SplitCategories,
                    Left = ReadDecisionTree(nodes, node.LeftChild),
                    Right = ReadDecisionTree(nodes, node.RightChild),
                    ClassDistribution = ReadClassDistribution(node.ClassDistribution),
                });

            default:
                throw new InvalidOperationException("Unknown split type: " + node.SplitType);
            }
        }