public void TryMatchRelationType()
        {
            var dataSet         = new RelationRatingTestData.SingleMatchUsingSameTrait();
            var childTraits     = new RelationTraitCache.ChildTraits <float>(dataSet.FloatTraitValues);
            var childTraitsList = new List <RelationTraitCache.ChildTraits <float> > {
                childTraits, childTraits
            };
            var relationArray       = new IRelation <float>[] { m_FloatRelation, m_FloatRelation };
            var relationRatingsList = new List <Dictionary <RelationDataPair, float> >().Fill(2);
            var dataPairs           = new [] { new RelationDataPair(0, 1), new RelationDataPair(1, 0) };
            var memberRatings       = new []
            {
                // start with one of the members having no matches, to test the failure case
                TestUtils.RandomRatings(), new Dictionary <int, float>()
            };

            // this index resetting is normally done by the function that wraps this function
            RelationRatingTransform.CurrentRelationPairIndex = 0;
            Assert.False(RelationRatingTransform.RateMatches(relationArray, childTraitsList, dataPairs,
                                                             memberRatings, relationRatingsList));

            // give the member with no matches some matches, which should result in the whole type passing
            memberRatings[1] = TestUtils.RandomRatings();
            RelationRatingTransform.CurrentRelationPairIndex = 0;
            Assert.True(RelationRatingTransform.RateMatches(relationArray, childTraitsList, dataPairs,
                                                            memberRatings, relationRatingsList));

            VerifyRelationRatings(relationRatingsList[0], childTraits);
            VerifyRelationRatings(relationRatingsList[1], childTraits);
        }
 static void VerifyRelationRatings <T>(Dictionary <RelationDataPair, float> ratings,
                                       RelationTraitCache.ChildTraits <T> childTraits, int greaterThanCount = 0)
 {
     Assert.Greater(ratings.Count, greaterThanCount);
     foreach (var kvp in ratings)
     {
         // make sure we don't use the same data for both members
         Assert.AreNotEqual(kvp.Key.Child1, kvp.Key.Child2);
         Assert.True(childTraits.One.ContainsKey(kvp.Key.Child1));
         Assert.True(childTraits.Two.ContainsKey(kvp.Key.Child2));
         Assert.Greater(kvp.Value, 0f);
     }
 }
        public void TryMatchSingleRelation()
        {
            var dataSet = new RelationRatingTestData.SingleMatchUsingSameTrait();
            // both members using the same trait is common - Distance & Elevation have both use "pose"
            var childTraits     = new RelationTraitCache.ChildTraits <float>(dataSet.FloatTraitValues);
            var relationRatings = new Dictionary <RelationDataPair, float>();

            // if one of the relation members has no matches, this relation can't match
            Assert.False(RelationRatingTransform.RateMatches(m_FloatRelation, childTraits,
                                                             dataSet.MemberOneRatings, new Dictionary <int, float>(), relationRatings));

            // once that same member has matches, we should be able to match this relation
            Assert.True(RelationRatingTransform.RateMatches(m_FloatRelation, childTraits,
                                                            dataSet.MemberOneRatings, dataSet.MemberTwoRatings, relationRatings));

            VerifyRelationRatings(relationRatings, childTraits);
        }
        /// <summary>
        /// Rate all possible matches for a single relation
        /// </summary>
        /// <param name="relation">The relation to find matches for</param>
        /// <param name="traits">References to the trait values used by relations</param>
        /// <param name="member1Ratings">Match ratings for the first member</param>
        /// <param name="member2Ratings">Match ratings for the second member</param>
        /// <param name="relationRatings">Output mapping of data pair to match rating</param>
        /// <typeparam name="T">The data type the Relation uses</typeparam>
        /// <returns>True if any matches were found, false otherwise</returns>
        public static bool RateMatches <T>(IRelation <T> relation,
                                           RelationTraitCache.ChildTraits <T> traits,
                                           Dictionary <int, float> member1Ratings,
                                           Dictionary <int, float> member2Ratings,
                                           Dictionary <RelationDataPair, float> relationRatings)
        {
            relationRatings.Clear();
            var child1TraitValues = traits.One;
            var child2TraitValues = traits.Two;

            foreach (var id1 in member1Ratings.Keys)
            {
                if (!child1TraitValues.TryGetValue(id1, out var value1))
                {
                    continue;
                }

                foreach (var id2 in member2Ratings.Keys)
                {
                    // matches for each child must have different IDs
                    if (id2 == id1)
                    {
                        continue;
                    }

                    // Both members must have the trait value present
                    if (!child2TraitValues.TryGetValue(id2, out var value2))
                    {
                        continue;
                    }

                    var relationRating = relation.RateDataMatch(ref value1, ref value2);
                    // if these two pieces of data did not match this relation, they cannot be used
                    if (relationRating <= 0f)
                    {
                        continue;
                    }

                    relationRatings.Add(new RelationDataPair(id1, id2), relationRating);
                }
            }

            return(relationRatings.Count > 0);
        }
        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]);
        }