Esempio n. 1
0
void SgUctTree::MergeChildren(std::size_t allocatorId, const SgUctNode& node,
                              const std::vector<SgMoveInfo>& moves,
                              bool deleteChildTrees)
{
    SG_ASSERT(Contains(node));
    // Parameters are const-references, because only the tree is allowed
    // to modify nodes
    SgUctNode& nonConstNode = const_cast<SgUctNode&>(node);
    size_t nuNewChildren = moves.size();

    if (nuNewChildren == 0)
    {
        // Write order dependency
        nonConstNode.SetNuChildren(0);
        SgSynchronizeThreadMemory();
        nonConstNode.SetFirstChild(0);
        return;
    }

    SgUctAllocator& allocator = Allocator(allocatorId);
    SG_ASSERT(allocator.HasCapacity(nuNewChildren));

    const SgUctNode* newFirstChild = allocator.Finish();
    std::size_t parentCount = allocator.Create(moves);
    
    // Update new children with data in old children
    for (std::size_t i = 0; i < moves.size(); ++i) 
    {
        SgUctNode* newChild = const_cast<SgUctNode*>(&newFirstChild[i]);
        for (SgUctChildIterator it(*this, node); it; ++it)
        {
            const SgUctNode& oldChild = *it;
            if (oldChild.Move() == moves[i].m_move)
            {
                newChild->MergeResults(oldChild);
                newChild->SetKnowledgeCount(oldChild.KnowledgeCount());
                if (! deleteChildTrees)
                {
                    newChild->SetPosCount(oldChild.PosCount());
                    parentCount += oldChild.MoveCount();
                    if (oldChild.HasChildren())
                    {
                        newChild->SetFirstChild(oldChild.FirstChild());
                        newChild->SetNuChildren(oldChild.NuChildren());
                    }
                }
                break;
            }
        }
    }
    nonConstNode.SetPosCount(parentCount);

    // Write order dependency: We do not want an SgUctChildIterator to
    // run past the end of a node's children, which can happen if one
    // is created between the two statements below. We modify node in
    // such a way so as to avoid that.
    if (nonConstNode.NuChildren() < (int)nuNewChildren)
    {
        nonConstNode.SetFirstChild(newFirstChild);
    SgSynchronizeThreadMemory();
        nonConstNode.SetNuChildren(nuNewChildren);
    }
    else
    {
        nonConstNode.SetNuChildren(nuNewChildren);
    SgSynchronizeThreadMemory();
        nonConstNode.SetFirstChild(newFirstChild);
    }
}
Esempio n. 2
0
/** Recursive function used by SgUctTree::ExtractSubtree and
    SgUctTree::CopyPruneLowCount.
    @param target The target tree.
    @param targetNode The target node; it is already created but the content
    not yet copied
    @param node The node in the source tree to be copied.
    @param minCount The minimum count (SgUctNode::MoveCount()) of a non-root
    node in the source tree to copy
    @param currentAllocatorId The current node allocator. Will be incremented
    in each call to CopySubtree to use node allocators of target tree evenly.
    @param warnTruncate Print warning to SgDebug() if tree was
    truncated (e.g due to reassigning nodes to different allocators)
    @param[in,out] abort Flag to abort copying. Must be initialized to false
    by top-level caller
    @param timer
    @param maxTime See ExtractSubtree()
*/
void SgUctTree::CopySubtree(SgUctTree& target, SgUctNode& targetNode,
                            const SgUctNode& node, std::size_t minCount,
                            std::size_t& currentAllocatorId,
                            bool warnTruncate, bool& abort, SgTimer& timer,
                            double maxTime) const
{
    SG_ASSERT(Contains(node));
    SG_ASSERT(target.Contains(targetNode));
    targetNode.CopyDataFrom(node);

    if (! node.HasChildren() || node.MoveCount() < minCount)
        return;

    SgUctAllocator& targetAllocator = target.Allocator(currentAllocatorId);
    int nuChildren = node.NuChildren();
    if (! abort)
    {
        if (! targetAllocator.HasCapacity(nuChildren))
        {
            // This can happen even if target tree has same maximum number of
            // nodes, because allocators are used differently.
            if (warnTruncate)
                SgDebug() <<
                "SgUctTree::CopySubtree: Truncated (allocator capacity)\n";
            abort = true;
        }
        if (timer.IsTimeOut(maxTime, 10000))
        {
            if (warnTruncate)
                SgDebug() << "SgUctTree::CopySubtree: Truncated (max time)\n";
            abort = true;
        }
        if (SgUserAbort())
        {
            if (warnTruncate)
                SgDebug() << "SgUctTree::CopySubtree: Truncated (aborted)\n";
            abort = true;
        }
    }
    if (abort)
    {
        // Don't copy the children and set the pos count to zero (should
        // reflect the sum of children move counts)
        targetNode.SetPosCount(0);
        return;
    }

    SgUctNode* firstTargetChild = targetAllocator.Finish();
    targetNode.SetFirstChild(firstTargetChild);
    targetNode.SetNuChildren(nuChildren);

    // Create target nodes first (must be contiguous in the target tree)
    targetAllocator.CreateN(nuChildren);

    // Recurse
    SgUctNode* targetChild = firstTargetChild;
    for (SgUctChildIterator it(*this, node); it; ++it, ++targetChild)
    {
        const SgUctNode& child = *it;
        ++currentAllocatorId; // Cycle to use allocators uniformly
        if (currentAllocatorId >= target.NuAllocators())
            currentAllocatorId = 0;
        CopySubtree(target, *targetChild, child, minCount, currentAllocatorId,
                    warnTruncate, abort, timer, maxTime);
    }
}