public void Dispose()
 {
     MatchBuffer?.Dispose();
     MetaEnumerator?.Dispose();
     MatchBuffer    = null;
     MetaEnumerator = null;
 }
        public GroupSearchData(int matchBufferCapacity, int[] memberIndices, Dictionary <int, float>[] allMemberRatings)
        {
            MatchBuffer        = new SetMatchesBuffer(memberIndices.Length, matchBufferCapacity);
            MemberRatings      = new Dictionary <int, float> [memberIndices.Length];
            ClaimedCombination = new int[memberIndices.Length];

            // gather set member ratings from global collections & compact it into local form
            for (var i = 0; i < memberIndices.Length; i++)
            {
                MemberRatings[i] = allMemberRatings[memberIndices[i]];
            }

            MetaEnumerator = new RatingMetaEnumerator(MemberRatings);
        }
예제 #3
0
        void ProcessStage(List <int> workingIndices, List <int> outputIndices,
                          int[][] allSetMemberIndices,
                          RelationDataPair[][] allLocalRelationIndexPairs,
                          RelationRatingsData[] allRelationRatings,
                          float[] allSetOrderWeights,
                          GroupSearchData[] allGroupSearchData,
                          RelationMembership[][] allRelationMemberships,
                          Exclusivity[] allMemberExclusivities,
                          Dictionary <int, float>[] allMemberRatings,
                          ref int[] allMemberAssignments)
        {
            if (workingIndices.Count == 0)
            {
                IsComplete = true;
                return;
            }

            if (m_TickCount == 0)
            {
                outputIndices.Clear();
                m_MemberAssignments.Clear();
                // Determine the order we are going to answer Groups.
                CalculateSolveOrder(allSetOrderWeights, AllGroupPriorities, workingIndices, m_AllOrderPairs);
                var setCount = m_AllOrderPairs.Count;
                m_SetsPerTick = Mathf.Clamp(Mathf.CeilToInt(setCount / (float)FrameBudget), 1, setCount);
            }

            // if we need to force completion, setting the end index to the last one will force all groups to solve
            var endIndex = NeedsCompletion ? m_AllOrderPairs.Count
                : Mathf.Clamp(m_SolveIndex + m_SetsPerTick, m_SolveIndex, m_AllOrderPairs.Count);

            for (var solveIndex = m_SolveIndex; solveIndex < endIndex; solveIndex++)
            {
                var kvp             = m_AllOrderPairs[solveIndex];
                var setIndex        = kvp.Key;
                var queryId         = SetMatchIds[setIndex].queryID;
                var memberIndices   = allSetMemberIndices[setIndex];
                var localPairs      = allLocalRelationIndexPairs[setIndex];
                var relationRatings = allRelationRatings[setIndex];
                var searchData      = allGroupSearchData[setIndex];
                var matchBuffer     = searchData.MatchBuffer;
                matchBuffer.Reset();

                // determine how many options we should try for each member before stopping
                var hasRelations    = localPairs.Length > 0;
                var searchSpaceSize = GetGroupSearchSpaceSize(memberIndices, allMemberRatings);
                // there's no options available for this group, skip it.
                if (searchSpaceSize == 0)
                {
                    continue;
                }

                var portion = GetSearchPortion(searchSpaceSize, SearchSpacePortionCurve, hasRelations);

                GetIterationTargets(portion, searchData.MemberRatings, searchData.MetaEnumerator.TargetDepths);

                m_MetaEnumerator = searchData.MetaEnumerator;
                m_MetaEnumerator.RefreshEnumerators();
                m_MetaEnumerator.Reset();
                m_MetaEnumerator.MoveNext(); // get enumerator into initial valid state

                if (!PreviousMatches.TryGetValue(queryId, out var record))
                {
                    record = new PreviousSetMatches(memberIndices.Length);
                    PreviousMatches.Add(queryId, record);
                }

                /*  The critical loop where we search the set's combination space happens here, in either function.
                 *  There are 2 different versions of our inner combination loop.
                 *
                 *  1) for Sets with at least one Relation, we filter during the loop only based on whether
                 *     the combination satisfies all Relations. We only do duplicate assignment &
                 *     data availability checks later, when picking the best match.
                 *
                 *  2) for Sets with no Relations, we check duplicate assignment & previous use during the loop,
                 *     and anything that passes those checks is valid.
                 */
                var matchFound = hasRelations ? TryCombinations(searchData.MatchBuffer, relationRatings, localPairs)
                                              : TryCombinationsWithoutRelations(searchData, record);

                // if we didn't find any matches for this set during our search, give up and move on.
                if (!matchFound)
                {
                    continue;
                }

                // if we did find matches, find the highest rated one and do any picking between ties necessary
                var chosenIndex = BestAvailableMatch(matchBuffer, record, hasRelations);
                if (chosenIndex < 0)
                {
                    continue;
                }

                // take our chosen match and assign its keys to set members in a staging collection -
                // this isn't final assignment, since we might have to roll back later.
                var begin = chosenIndex * matchBuffer.SetSize;
                var end   = begin + matchBuffer.SetSize;
                for (var i = begin; i < end; i++)
                {
                    var assignedDataId    = matchBuffer.DataIds[i];
                    var globalMemberIndex = memberIndices[i - begin];
                    m_MemberAssignments[globalMemberIndex] = assignedDataId;
                }

                matchBuffer.CombinationAtRatingIndex(chosenIndex, searchData.ClaimedCombination);

                // the following stages - marking data used & filling results - will use these as their working indices
                if (!outputIndices.Contains(setIndex))
                {
                    outputIndices.Add(setIndex);
                }

                // if this is anything except the last Set to be solved in the cycle,
                // we need to remove the appropriate possibilities from the remaining sets
                if (solveIndex >= m_AllOrderPairs.Count - 1)
                {
                    continue;
                }

                for (var i = solveIndex + 1; i < m_AllOrderPairs.Count; i++)
                {
                    var otherSetIndex = m_AllOrderPairs[i].Key;
                    RemoveClaimedData(searchData.ClaimedCombination, memberIndices,
                                      allSetMemberIndices[otherSetIndex], allMemberExclusivities, allMemberRatings);
                }
            }

            m_SolveIndex = endIndex;
            m_TickCount++;

            if (endIndex == m_AllOrderPairs.Count)
            {
                // finalize our assignments
                foreach (var kvp in m_MemberAssignments)
                {
                    allMemberAssignments[kvp.Key] = kvp.Value;
                }

                IsComplete = true;
            }
        }