예제 #1
0
        // helper to implement Constraint.SatisfiesConstraint
        internal static ConstraintSatisfaction SatisfiesContraint(Model model, ValueCombination combination, ParameterInteraction interaction)
        {
            Debug.Assert(model != null && combination != null && interaction != null);

            var parameterMap = combination.ParameterToValueMap;

            for (int i = 0; i < interaction.Parameters.Count; i++)
            {
                if (!parameterMap.ContainsKey(interaction.Parameters[i]))
                {
                    return(ConstraintSatisfaction.InsufficientData);
                }
            }

            for (int i = 0; i < interaction.Combinations.Count; i++)
            {
                if (ParameterInteractionTable.MatchCombination(interaction.Combinations[i], combination))
                {
                    if (interaction.Combinations[i].State == ValueCombinationState.Excluded)
                    {
                        return(ConstraintSatisfaction.Unsatisfied);
                    }
                }
            }

            return(ConstraintSatisfaction.Satisfied);
        }
예제 #2
0
        // add this value to the candidate
        private static void CreateProposedCandidate(ValueCombination value, int[] baseCandidate, int[] proposed)
        {
            baseCandidate.CopyTo(proposed, 0);

            foreach (var valuePair in value.ParameterToValueMap)
            {
                proposed[valuePair.Key] = valuePair.Value;
            }
        }
예제 #3
0
 public ParameterInteraction(ParameterInteraction interaction)
 {
     this.parameters = new List <int>(interaction.Parameters);
     foreach (var combination in interaction.Combinations)
     {
         var newCombination = new ValueCombination(combination);
         Combinations.Add(newCombination);
     }
 }
예제 #4
0
        // can this value be added to this candidate
        private static bool IsCompatibleValue(ValueCombination value, int[] candidate)
        {
            foreach (int i in value.Keys)
            {
                if (candidate[i] != value.ParameterToValueMap[i] && candidate[i] != -1)
                {
                    return(false);
                }
            }

            return(true);
        }
예제 #5
0
        // add this value to the candidate
        private static int[] CreateProposedCandidate(ValueCombination value, int[] baseCandidate)
        {
            int[] proposed = new int[baseCandidate.Length];
            baseCandidate.CopyTo(proposed, 0);

            foreach (var valuePair in value.ParameterToVaueMap)
            {
                proposed[valuePair.Key] = valuePair.Value;
            }

            return(proposed);
        }
예제 #6
0
        // do all the values in subset match with the whole
        public static bool MatchCombination(ValueCombination subSet, ValueCombination whole)
        {
            var wholeParameterMap  = whole.ParameterToValueMap;
            var subSetParameterMap = subSet.ParameterToValueMap;

            foreach (var key in subSet.Keys)
            {
                if (!wholeParameterMap.ContainsKey(key) ||
                    subSetParameterMap[key] != wholeParameterMap[key])
                {
                    return(false);
                }
            }

            return(true);
        }
예제 #7
0
        // create all the values for each combination
        private void GenerateValueCombinations(Model model)
        {
            for (int i = 0; i < Interactions.Count; i++)
            {
                var interaction = Interactions[i];
                var valueTable  = GenerateValueTable(model.Parameters, interaction);

                for (int j = 0; j < valueTable.Count; j++)
                {
                    var    values      = valueTable[j];
                    var    combination = new ValueCombination(values, interaction);
                    var    tag         = model.DefaultVariationTag;
                    double weight      = 1.0;

                    interaction.Combinations.Add(combination);
                    for (int k = 0; k < values.Length; k++)
                    {
                        var value = model.Parameters[interaction.Parameters[k]][values[k]];

                        if (value is ParameterValue)
                        {
                            var parameterValue = (ParameterValue)value;
                            if (parameterValue.Weight != 1.0)
                            {
                                weight = weight == 1.0 ? parameterValue.Weight : Math.Max(weight, parameterValue.Weight);
                            }

                            if (parameterValue.Tag != null && parameterValue.Tag != model.DefaultVariationTag)
                            {
                                if (tag != model.DefaultVariationTag)
                                {
                                    combination.State = ValueCombinationState.Excluded;
                                }
                                else
                                {
                                    tag = parameterValue.Tag;
                                }
                            }
                        }
                    }

                    combination.Weight = weight;
                    combination.Tag    = tag;
                }
            }
        }
예제 #8
0
        // helper to implement Constraint.SatisfiesConstraint
        internal static ConstraintSatisfaction SatisfiesContraint(Model model, ValueCombination combination, ParameterInteraction interaction)
        {
            Debug.Assert(model != null && combination != null && interaction != null);

            if (!interaction.Parameters.All((i) => combination.ParameterToVaueMap.ContainsKey(i)))
            {
                return(ConstraintSatisfaction.InsufficientData);
            }

            var matches = interaction.Combinations.Where((c) => ParameterInteractionTable.MatchCombination(c, combination));

            if (matches.Any((c) => c.State == ValueCombinationState.Excluded))
            {
                return(ConstraintSatisfaction.Unsatisfied);
            }

            return(ConstraintSatisfaction.Satisfied);
        }
예제 #9
0
 public ValueCombination(ValueCombination combination)
 {
     this.parameterToValueMap = new Dictionary <int, int>(combination.ParameterToVaueMap);
     this.State = combination.State;
 }
예제 #10
0
        // this is the actual generation function
        // returns a list of indices that allow lookup of the actual value in the model
        private static IList <VariationIndexTagPair> GenerateVariationIndices <T>(ParameterInteractionTable <T> interactions, int variationSize, int seed, long maxVariations, object defaultTag) where T : new()
        {
            Random random = new Random(seed);
            List <VariationIndexTagPair> variations = new List <VariationIndexTagPair>();

            // while there a uncovered values
            while (!interactions.IsCovered())
            {
                int[]  candidate    = new int[variationSize];
                object variationTag = defaultTag;

                // this is a scatch variable so new arrays won't be allocated for every candidate
                int[] proposedCandidate = new int[variationSize];
                for (int i = 0; i < candidate.Length; i++)
                {
                    // -1 indicates an empty slot
                    candidate[i] = -1;
                }

                IEnumerable <ParameterInteraction> candidateInteractions = interactions.Interactions;
                // while there are empty slots
                while (candidate.Any((i) => i == -1))
                {
                    // if all the slots are empty
                    if (candidate.All((i) => i == -1))
                    {
                        // then pick the first uncovered combination from the most uncovered parameter interaction
                        int mostUncovered =
                            interactions.Interactions.Max((i) => i.GetUncoveredCombinationsCount());

                        var interaction = interactions.Interactions.First((i) => i.GetUncoveredCombinationsCount() == mostUncovered);
                        var combination = interaction.Combinations.First((c) => c.State == ValueCombinationState.Uncovered);

                        foreach (var valuePair in combination.ParameterToValueMap)
                        {
                            candidate[valuePair.Key] = valuePair.Value;
                        }

                        variationTag      = combination.Tag == null || combination.Tag == defaultTag ? variationTag : combination.Tag;
                        combination.State = ValueCombinationState.Covered;
                    }
                    else
                    {
                        // find interactions that aren't covered by the current candidate variation
                        var incompletelyCoveredInteractions =
                            from interaction in candidateInteractions
                            where interaction.Parameters.Any((i) => candidate[i] == -1)
                            select interaction;

                        candidateInteractions = incompletelyCoveredInteractions;
                        // find values that can be added to the current candidate
                        var compatibleValues = new List <ValueCombination>();
                        foreach (var interaction in incompletelyCoveredInteractions)
                        {
                            foreach (var combination in interaction.Combinations)
                            {
                                if (IsCompatibleValue(combination, candidate))
                                {
                                    compatibleValues.Add(combination);
                                }
                            }
                        }

                        // get the uncovered values
                        var uncoveredValues = compatibleValues.Where((v) => v.State == ValueCombinationState.Uncovered).ToList();

                        // calculate what the candidate will look like if add an uncovered value
                        var proposedCandidates = new List <CandidateCoverage>();
                        foreach (var uncoveredValue in uncoveredValues)
                        {
                            CreateProposedCandidate(uncoveredValue, candidate, proposedCandidate);

                            if (!IsExcluded(interactions.ExcludedCombinations, proposedCandidate))
                            {
                                var coverage = new CandidateCoverage
                                {
                                    Value         = uncoveredValue,
                                    CoverageCount = uncoveredValues.Count((v) => IsCovered(v, proposedCandidate)),
                                };

                                proposedCandidates.Add(coverage);
                            }
                        }

                        // if any of the proposed candidates isn't exclude
                        if (proposedCandidates.Count > 0)
                        {
                            // find the value that will cover the most combinations
                            int              maxCovered    = proposedCandidates.Max((c) => c.CoverageCount);
                            double           maxWeight     = proposedCandidates.Where((c) => c.CoverageCount == maxCovered).Max((c) => c.Value.Weight);
                            ValueCombination proposedValue = proposedCandidates.First((c) => c.CoverageCount == maxCovered && c.Value.Weight == maxWeight).Value;

                            // add this value to candidate and mark all values as such
                            foreach (var valuePair in proposedValue.ParameterToValueMap)
                            {
                                candidate[valuePair.Key] = valuePair.Value;
                            }

                            variationTag = proposedValue.Tag == null || proposedValue.Tag == defaultTag ? variationTag : proposedValue.Tag;

                            // get the newly covered values so they can be marked
                            var newlyCoveredValue = uncoveredValues.Where((v) => IsCovered(v, candidate)).ToList();

                            foreach (var value in newlyCoveredValue)
                            {
                                value.State = ValueCombinationState.Covered;
                            }
                        }
                        else
                        {
                            // no uncovered values can be added with violating a constraint, add a random covered value
                            var compatibleWeightBuckets       = compatibleValues.GroupBy((v) => v.Weight).OrderByDescending((v) => v.Key);
                            ValueCombination value            = null;
                            bool             combinationFound = false;
                            foreach (var bucket in compatibleWeightBuckets)
                            {
                                int count    = bucket.Count();
                                int attempts = 0;

                                do
                                {
                                    value = bucket.ElementAt(random.Next(count - 1));
                                    CreateProposedCandidate(value, candidate, proposedCandidate);

                                    if (!interactions.ExcludedCombinations.Any((c) => IsCovered(c, proposedCandidate)))
                                    {
                                        combinationFound = true;
                                    }

                                    attempts++;

                                    // this is a heuristic, since we're pulling random values just going to count probably
                                    // means we've attempted duplicates, going to 2 * count means we've probably tried
                                    // everything at least once
                                    if (attempts > count * 2)
                                    {
                                        break;
                                    }
                                }while (!combinationFound);

                                if (combinationFound)
                                {
                                    break;
                                }
                            }

                            if (!combinationFound)
                            {
                                throw new InternalVariationGenerationException("Unable to find candidate with no exclusions.");
                            }

                            // add this value to candidate and mark all values as such

                            foreach (var valuePair in value.ParameterToValueMap)
                            {
                                candidate[valuePair.Key] = valuePair.Value;
                            }

                            variationTag = value.Tag == null || value.Tag == defaultTag ? variationTag : value.Tag;
                        }
                    }
                }

                variations.Add(new VariationIndexTagPair {
                    Indices = candidate, Tag = variationTag
                });

                // more variations than are need to exhaustively test the model have been adde
                if (variations.Count > maxVariations)
                {
                    throw new InternalVariationGenerationException("More variations than an exhaustive suite produced.");
                }
            }

            return(variations);
        }
예제 #11
0
 public ValueCombination(ValueCombination combination)
 {
     this.parameterToValueMap = new Dictionary <int, int>(combination.ParameterToValueMap);
     this.State = combination.State;
     keys       = new KeyCollection(parameterToValueMap.Keys);
 }
예제 #12
0
 /// <summary>
 /// Calcultes whether the specified value satisfies the constraint or has insufficient data to do so.
 /// </summary>
 /// <param name="model">The model.</param>
 /// <param name="combination">The value.</param>
 /// <returns>The calculated result.</returns>
 internal abstract ConstraintSatisfaction SatisfiesContraint(Model <T> model, ValueCombination combination);
예제 #13
0
        // this is the actual generation function
        // returns a list of indices that allow lookup of the actual value in the model
        private static IList <int[]> GenerateVariationIndices(ParameterInteractionTable interactions, int variationSize, int seed, int maxVariations)
        {
            Random       random     = new Random(seed);
            List <int[]> variations = new List <int[]>();

            // while there a uncovered values
            while (!interactions.IsCovered())
            {
                int[] candidate = new int[variationSize];
                for (int i = 0; i < candidate.Length; i++)
                {
                    // -1 indicates an empty slot
                    candidate[i] = -1;
                }

                // while there are empty slots
                while (candidate.Any((i) => i == -1))
                {
                    // if all the slots are empty
                    if (candidate.All((i) => i == -1))
                    {
                        // then pick the first uncovered combination from the most uncovered parameter interaction
                        int mostUncovered =
                            interactions.Interactions.Max((i) => i.GetUncoveredCombinationsCount());

                        var interaction = interactions.Interactions.First((i) => i.GetUncoveredCombinationsCount() == mostUncovered);
                        var combination = interaction.Combinations.First((c) => c.State == ValueCombinationState.Uncovered);

                        foreach (var valuePair in combination.ParameterToVaueMap)
                        {
                            candidate[valuePair.Key] = valuePair.Value;
                        }

                        combination.State = ValueCombinationState.Covered;
                    }
                    else
                    {
                        // find interactions that aren't covered by the current candidate variation
                        var incompletelyCoveredInteractions =
                            from interaction in interactions.Interactions
                            where interaction.Parameters.Any((i) => candidate[i] == -1)
                            select interaction;

                        // find values that can be added to the current candidate
                        var compatibleValues =
                            from interaction in incompletelyCoveredInteractions
                            from combination in interaction.Combinations
                            where IsCompatibleValue(combination, candidate)
                            select combination;

                        // get the uncovered values
                        var uncoveredValues = compatibleValues.Where((v) => v.State == ValueCombinationState.Uncovered).ToList();

                        // calculate what the candidate will look like if add an uncovered value
                        var proposedCandidates =
                            from value in uncoveredValues
                            select new
                        {
                            Value     = value,
                            Candidate = CreateProposedCandidate(value, candidate)
                        };

                        // if any of the proposed candidates isn't exclude
                        if (proposedCandidates.Any((a) => !IsExcluded(interactions.ExcludedCombinations(), a.Candidate)))
                        {
                            // find the value that will cover the most combinations
                            int maxCovered = proposedCandidates.Max(
                                (a) => uncoveredValues.Count(
                                    (v) => IsCovered(v, a.Candidate) &&
                                    !IsExcluded(interactions.ExcludedCombinations(), a.Candidate)));

                            ValueCombination proposedValue = proposedCandidates.First(
                                (a) => uncoveredValues.Count(
                                    (v) => IsCovered(v, a.Candidate) &&
                                    !IsExcluded(interactions.ExcludedCombinations(), a.Candidate)) == maxCovered).Value;

                            // add this value to candidate and mark all values as such

                            foreach (var valuePair in proposedValue.ParameterToVaueMap)
                            {
                                candidate[valuePair.Key] = valuePair.Value;
                            }

                            // get the newly covered values so they can be marked
                            var newlyCoveredValue = uncoveredValues.Where((v) => IsCovered(v, candidate)).ToList();

                            foreach (var value in newlyCoveredValue)
                            {
                                value.State = ValueCombinationState.Covered;
                            }
                        }
                        else
                        {
                            // no uncovered values can be added with violating a constraint, add a random covered value
                            int count    = compatibleValues.Count();
                            int attempts = 0;
                            ValueCombination value;
                            int[]            proposedCandidate;
                            do
                            {
                                value             = compatibleValues.ElementAt(random.Next(count - 1));
                                proposedCandidate = CreateProposedCandidate(value, candidate);

                                // this is a heuristic, since we're pulling random values just going to count probably
                                // means we've attempted duplicates, going to 2 * count means we've probably tried
                                // everything at least once
                                if (attempts > count * 2)
                                {
                                    throw new InternalVariationGenerationException("Unable to find candidate with no exclusions.");
                                }

                                attempts++;
                            }while (interactions.ExcludedCombinations().Any((c) => IsCovered(c, CreateProposedCandidate(value, candidate))));

                            // add this value to candidate and mark all values as such

                            foreach (var valuePair in value.ParameterToVaueMap)
                            {
                                candidate[valuePair.Key] = valuePair.Value;
                            }
                        }
                    }
                }

                variations.Add(candidate);

                // more variations than are need to exhaustively test the model have been adde
                if (variations.Count > maxVariations)
                {
                    throw new InternalVariationGenerationException("More variations than an exhaustive suite produced.");
                }
            }

            return(variations);
        }
예제 #14
0
 // can this value be added to this candidate
 private static bool IsCompatibleValue(ValueCombination value, int[] candidate)
 {
     return(value.ParameterToVaueMap.Keys
            .All((i) => candidate[i] == value.ParameterToVaueMap[i] || candidate[i] == -1));
 }
예제 #15
0
 // do all the values in subset match with the whole
 public static bool MatchCombination(ValueCombination subSet, ValueCombination whole)
 {
     return(subSet.ParameterToVaueMap.Keys
            .All((i) => whole.ParameterToVaueMap.ContainsKey(i) &&
                 subSet.ParameterToVaueMap[i] == whole.ParameterToVaueMap[i]));
 }