/// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="parentTree"></param>
        /// <param name="maxCacheSize"></param>
        public MCTSNodeCacheArrayPurgeableSet(MCTSTree parentTree, int maxCacheSize)
        {
            ParentTree   = parentTree;
            MaxCacheSize = maxCacheSize;

            // Initialize the sub-caches
            subCaches = new MCTSNodeCacheArrayPurgeable[MAX_SUBCACHES];
            for (int i = 0; i < MAX_SUBCACHES; i++)
            {
                subCaches[i] = new MCTSNodeCacheArrayPurgeable(parentTree, maxCacheSize / MAX_SUBCACHES);
            }
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="parentTree"></param>
        /// <param name="definitiveMaxCacheSize"></param>
        /// <param name="estimatedNumNodesInSearch"></param>
        public MCTSNodeCacheArrayPurgeableSet(MCTSTree parentTree,
                                              int definitiveMaxCacheSize,
                                              int estimatedNumNodesInSearch)
        {
            ParentTree   = parentTree;
            MaxCacheSize = definitiveMaxCacheSize;

            // Compute number of subcaches, increasing as a function of estimates search size
            // (because degree of concurrency rises with size of batches and search.
            NumSubcaches = (int)StatUtils.Bounded(2 * MathF.Log2((float)estimatedNumNodesInSearch / 1000), 3, 16);

            // Initialize the sub-caches
            subCaches = new MCTSNodeCacheArrayPurgeable[NumSubcaches];
            for (int i = 0; i < NumSubcaches; i++)
            {
                subCaches[i] = new MCTSNodeCacheArrayPurgeable(parentTree, definitiveMaxCacheSize / NumSubcaches);
            }
        }