// 5 members with 3 relations between them
            // member 1 has relations to 2 & 3
            // member 4 has a relation to member 3, member 5 has no relations
            public static SetExpectation GetMediumLargeSetCase(GroupRatingConfiguration ratingConfig)
            {
                var relationRatings = new RelationRatingsData().Initialize(3);

                relationRatings[0] = SimpleRelationRatings1;
                relationRatings[1] = SimpleRelationRatings2;
                relationRatings[2] = SimpleRelationRatings3;

                var memberContribution   = (0.8f + 0.9f + 0.72f + 0.5f + 0.3f) / 5f;
                var relationContribution = Mathf.Pow(0.75f * 0.6f * 0.4f, 1f / 3f);

                return(new SetExpectation()
                {
                    RatingConfiguration = ratingConfig,
                    // since we only have one relation, rated 0.75, it contributes all the relation ratings
                    //ApproximateExpectedRating = (memberContribution + relationContribution) * 0.5f,
                    ApproximateExpectedRating = GetExpected(memberContribution, relationContribution, ratingConfig),
                    Members = new[]
                    {
                        new KeyValuePair <int, float>(1, 0.8f),
                        new KeyValuePair <int, float>(4, 0.9f),
                        new KeyValuePair <int, float>(8, 0.72f),
                        new KeyValuePair <int, float>(3, 0.5f),
                        new KeyValuePair <int, float>(10, 0.3f),
                    },
                    RelationRatings = relationRatings,
                    LocalRelationIndices = new[]
                    {
                        new RelationDataPair(0, 1), new RelationDataPair(0, 2), new RelationDataPair(3, 2),
                    }
                });
            }
Beispiel #2
0
        public static bool TryMatchAllInternal(Relations relations,
                                               RelationTraitCache traits,
                                               RelationRatingsData ratings,
                                               Dictionary <int, float>[] memberRatings,
                                               RelationDataPair[] relationPairs)
        {
            if (relations.GetTypeCount(out IRelation <System.Int32>[] intRelations) > 0)
            {
                if (!traits.TryGetType(out List <RelationTraitCache.ChildTraits <System.Int32> > intTraits) ||
                    !RateMatches(intRelations, intTraits, relationPairs, memberRatings, ratings))
                {
                    return(false);
                }
            }

            if (relations.GetTypeCount(out IRelation <UnityEngine.Pose>[] poseRelations) > 0)
            {
                if (!traits.TryGetType(out List <RelationTraitCache.ChildTraits <UnityEngine.Pose> > poseTraits) ||
                    !RateMatches(poseRelations, poseTraits, relationPairs, memberRatings, ratings))
                {
                    return(false);
                }
            }

            if (relations.GetTypeCount(out IRelation <UnityEngine.Vector2>[] vector2Relations) > 0)
            {
                if (!traits.TryGetType(out List <RelationTraitCache.ChildTraits <UnityEngine.Vector2> > vector2Traits) ||
                    !RateMatches(vector2Relations, vector2Traits, relationPairs, memberRatings, ratings))
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Try to find matches for all Relations in a Set.
        /// </summary>
        /// <param name="relations">All relations in the set</param>
        /// <param name="traits">References to the trait values used by all relations</param>
        /// <param name="ratingData">Output list of dictionaries</param>
        /// <param name="memberRatings">The collection of all member ratings</param>
        /// <param name="relationPairs">The relation index pairs for this Set</param>
        /// <returns>True if all relations found at least 1 match, false otherwise</returns>
        public static bool TryMatchAll(Relations relations,
                                       RelationTraitCache traits,
                                       RelationRatingsData ratingData,
                                       Dictionary <int, float>[] memberRatings,
                                       RelationDataPair[] relationPairs)
        {
            CurrentRelationPairIndex = 0;
            foreach (var dictionary in ratingData)
            {
                dictionary.Clear();
            }

            return(TryMatchAllInternal(relations, traits, ratingData, memberRatings, relationPairs));
        }
            // this version should fail, because the member assignments do not form a valid Relation
            public static SetExpectation GetSimpleFailingSetCase()
            {
                var relationRatings = new RelationRatingsData().Initialize(1);

                relationRatings[0] = SimpleRelationRatings1;
                return(new SetExpectation()
                {
                    Members = new[]
                    {
                        new KeyValuePair <int, float>(4, 0.8f), new KeyValuePair <int, float>(2, 0.9f),
                    },
                    RelationRatings = relationRatings,
                    LocalRelationIndices = new[] { new RelationDataPair(0, 1) }
                });
            }
            // A very simple Set - 2 members with one Relation between them.
            public static SetExpectation GetSimpleSetCase(GroupRatingConfiguration ratingConfig)
            {
                var relationRatings = new RelationRatingsData().Initialize(1);

                relationRatings[0] = SimpleRelationRatings1;
                return(new SetExpectation()
                {
                    RatingConfiguration = ratingConfig,
                    // since we only have one relation, rated 0.75, it contributes all the relation ratings
                    //ApproximateExpectedRating = ((0.8f + 0.9f) * 0.5f + 0.75f) * 0.5f,
                    ApproximateExpectedRating = GetExpected((0.8f + 0.9f) * 0.5f, 0.75f, ratingConfig),
                    Members = new[]
                    {
                        new KeyValuePair <int, float>(1, 0.8f), new KeyValuePair <int, float>(4, 0.9f),
                    },
                    RelationRatings = relationRatings,
                    LocalRelationIndices = new[] { new RelationDataPair(0, 1) }
                });
            }
        public void TryMatchAll()
        {
            var dataSet    = new RelationRatingTestData.SingleMatchUsingSameTrait();
            var testObject = m_SetQueryTestObject;
            var relations  = TestUtils.GetRelations(testObject);

            var traitCache = new RelationTraitCache(relations);

            Assert.True(traitCache.TryGetType(out List <RelationTraitCache.ChildTraits <float> > floatTraits));
            traitCache.TryGetType(out List <RelationTraitCache.ChildTraits <Pose> > poseTraits);
            floatTraits[0] = new RelationTraitCache.ChildTraits <float>(dataSet.FloatTraitValues);
            // start with one of our trait values being empty of data, so we can test a failure case
            poseTraits[0] = new RelationTraitCache.ChildTraits <Pose>(new Dictionary <int, Pose>());

            var relationRatings    = new RelationRatingsData(relations);
            var memberRatingsArray = RandomRatingsArray(relations.children.Count);
            var relationIndexPairs = new RelationDataPair[relations.Count];

            for (var i = 0; i < relations.Count; i++)
            {
                // for the purposes of this test, we just want to see that the lower-level
                // abstraction that works on a per-type basis works for all types,
                // so it doesn't matter if the index pair data is accurate
                relationIndexPairs[i] = new RelationDataPair(i, i == relations.Count - 1 ? 0 : i + 1);
            }

            // because our pose relation has no trait data, it should fail and cause the whole result to be false
            Assert.False(RelationRatingTransform.TryMatchAll(relations, traitCache, relationRatings,
                                                             memberRatingsArray, relationIndexPairs));

            // assign usable data to the trait that had no values before, and then re-try - now it should succeed
            poseTraits[0] = new RelationTraitCache.ChildTraits <Pose>(dataSet.PoseTraitValues);

            Assert.True(RelationRatingTransform.TryMatchAll(relations, traitCache, relationRatings,
                                                            memberRatingsArray, relationIndexPairs));

            // The default set test prefab has a float and pose relation on it, so we expect 2
            Assert.AreEqual(2, relationRatings.Count);

            VerifyRelationRatings(relationRatings[0], floatTraits[0]);
            VerifyRelationRatings(relationRatings[1], poseTraits[0]);
        }
Beispiel #7
0
        /// <summary>
        /// For a Set with any Relations, iterate over a portion of possible combinations of member assignments.
        /// For each combination that satisfies all Relations, reduce Relation & member ratings into a single rating.
        /// </summary>
        /// <param name="matchBuffer">A buffer to record valid combinations with their ratings in</param>
        /// <param name="relationRatings">The Relation ratings for this single Set</param>
        /// <param name="localRelationPairs">The local relation index pairs for this Set</param>
        /// <returns></returns>
        bool TryCombinations(SetMatchesBuffer matchBuffer, RelationRatingsData relationRatings,
                             RelationDataPair[] localRelationPairs)
        {
            var config = RatingConfiguration;

            matchBuffer.Reset();
            do
            {
                var hypothesis = m_MetaEnumerator.Current;
                // determine if a given combination of member assignments is valid according to our Relations
                if (!TryRateAssignmentSet(hypothesis, relationRatings, localRelationPairs, config, out var rating))
                {
                    continue;
                }

                matchBuffer.Add(hypothesis, rating);
            }
            // this call produces the next combination to rate, until we reach our iteration target
            while (m_MetaEnumerator.MoveNext());

            // for Sets with Relations, we filter by availability and duplicates only after picking a match
            return(matchBuffer.Count > 0);
        }
Beispiel #8
0
        /// <summary>
        /// Verify that a given assignment hypothesis satisfies all Relations, and produce a rating for it if so.
        /// This function assumes that the Set has at least one Relation.
        /// For sets without relations, AverageMemberRating should be used instead.
        /// </summary>
        /// <param name="hypothesis">The assignment combination to verify the validity of</param>
        /// <param name="setRelationsRatings">The relation ratings for the Set</param>
        /// <param name="localRelationPairs">Pairs that map each relation's members within the local collections</param>
        /// <param name="ratingConfiguration">The configured weight to use for producing the final ratings</param>
        /// <param name="reducedRating">The final rating for the combination.  0 if the combination is invalid</param>
        /// <returns>True if the combination was valid, false otherwise</returns>
        internal static bool TryRateAssignmentSet(KeyValuePair <int, float>[] hypothesis,
                                                  RelationRatingsData setRelationsRatings,
                                                  RelationDataPair[] localRelationPairs,
                                                  GroupRatingConfiguration ratingConfiguration,
                                                  out float reducedRating)
        {
            // for every Relation, check if its member's assignments are valid within our hypothesis
            var relationRatings = 1f;

            for (var i = 0; i < localRelationPairs.Length; i++)
            {
                var ratings   = setRelationsRatings[i];
                var indexPair = localRelationPairs[i];
                var child1    = hypothesis[indexPair.Child1].Key;
                var child2    = hypothesis[indexPair.Child2].Key;
                // if this assignment pair doesn't satisfy this relation, we know to move onto another assignment combo
                if (!ratings.TryGetValue(new RelationDataPair(child1, child2), out var pairRating))
                {
                    reducedRating = 0f;
                    return(false);
                }

                relationRatings *= pairRating;
            }

            // combine our relation ratings just like our condition ones - the "inverse power" method
            var reducedRelationRating = Mathf.Pow(relationRatings, 1f / localRelationPairs.Length);

            // combine the relation & member ratings according to the configured weights
            var relationsWeighted = reducedRelationRating * (1f - ratingConfiguration.MemberMatchWeight);
            var membersWeighted   = AverageMemberRating(hypothesis) * ratingConfiguration.MemberMatchWeight;

            reducedRating = relationsWeighted + membersWeighted;

            return(true);
        }
Beispiel #9
0
        // for each Relation this member belongs to, if a data ID from member matches isn't found in that
        // relation's matches, remove that ID from the member's match ratings, because it can't work.
        internal void RemoveInvalidMemberMatches(RelationMembership[] memberships,
                                                 RelationRatingsData allRelationRatings,
                                                 Dictionary <int, float> memberRatings)
        {
            var memberKeys = memberRatings.Keys;

            foreach (var membership in memberships)
            {
                var removalBufferCounter  = 0;
                var singleRelationRatings = allRelationRatings[membership.RelationIndex].Keys;

                // the only difference between these branches is which relation child key we check against.
                // it's organized this way so that this if check is moved out of the two inner loops.
                if (membership.FirstMember)
                {
                    foreach (var memberKey in memberKeys)
                    {
                        var memberKeyFound = false;
                        foreach (var relationPair in singleRelationRatings)
                        {
                            if (relationPair.Child1 == memberKey)
                            {
                                memberKeyFound = true;
                                break;
                            }
                        }

                        if (memberKeyFound)
                        {
                            continue;
                        }

                        m_IdRemovalBuffer[removalBufferCounter] = memberKey;
                        removalBufferCounter++;
                    }
                }
                else
                {
                    foreach (var memberKey in memberKeys)
                    {
                        var memberKeyFound = false;
                        foreach (var relationPair in singleRelationRatings)
                        {
                            if (relationPair.Child2 == memberKey)
                            {
                                memberKeyFound = true;
                                break;
                            }
                        }

                        if (memberKeyFound)
                        {
                            continue;
                        }

                        m_IdRemovalBuffer[removalBufferCounter] = memberKey;
                        removalBufferCounter++;
                    }
                }

                for (var i = 0; i < removalBufferCounter; i++)
                {
                    memberRatings.Remove(m_IdRemovalBuffer[i]);
                }
            }
        }