/// <summary> /// Explores the input (sub-)space. Each invocation may return a different set. /// </summary> /// <returns> /// A (reasonably-sized) stream of vectors/values from the (sub-)space. /// </returns> public override IEnumerable<Vector> Explore() { if (TargetMatrix.Dimensions.Count == 0) { // No dimensions to explore, then yield one empty vector. yield return new Vector(); yield break; } ReadOnlyCollection<DimensionWithValues> dimensionValues = GetAllDimensionValues(); if (dimensionValues.Any(dim => dim.Values.Count == 0)) { yield break; // One of the dimensions is empty } if (dimensionValues.Count < _order) { // This is really non-sensical to ask for an n-wise strategy for a matrix with less than n dimensions // but I'd rather return a good default than throw. So I'll just cheat and do an exhaustive strategy instead ExhaustiveCombinatorialStrategy exhaustiveStrategy = new ExhaustiveCombinatorialStrategy(this); foreach (Vector v in exhaustiveStrategy.Explore()) yield return v; yield break; } CoveredPairwiseCombinations coveredCombinations = new CoveredPairwiseCombinations(); DimensionValueIndexCombination currentCombination = new DimensionValueIndexCombination(dimensionValues); DimensionIndexCombinationGenerator dimensionIndexGenerator = CreateDimensionIndexCombinationGenerator(dimensionValues); Vector currentVector = currentCombination.GenerateVector(); if (IsValidVector(currentVector)) { coveredCombinations.AddCoveredPairwiseCombinations(currentCombination, dimensionIndexGenerator); yield return currentVector; } PartialVectorConstraintChecker partialConstraintChecker = UsePartialConstraintChecker ? new PartialVectorConstraintChecker(dimensionValues, Constraints) : null; foreach (ReadOnlyCollection<int> currentDimensionsToCover in dimensionIndexGenerator.Generate()) { // Initialize the selection of values in the newly selected pairwise combination for (int i = 0; i < currentDimensionsToCover.Count; i++) { currentCombination[currentDimensionsToCover[i]] = 0; } while (true) { bool selectionSucceeded = SelectNextValuesForCurrentDimensionCombination(currentCombination, currentDimensionsToCover); if (!selectionSucceeded) { // We exhausted all combinations of values for the current pairwise combination // select the next pairwise combination break; } if (coveredCombinations.IsCombinationCovered(currentDimensionsToCover, currentCombination)) { continue; } if (partialConstraintChecker != null && !partialConstraintChecker.IsValidForApplicableConstraints(currentCombination, currentDimensionsToCover)) { // This combination is forbidden by constraints - carry on continue; } // Randomize other values, try at most MAXTRIES since we might hit invalid combinations for (int i = 0; i < MAXTRIES; i++) { List<int> remainingDimensionIndexes = Enumerable.Range(0, dimensionValues.Count) .Where(di => !currentDimensionsToCover.Contains(di)) // Don't randomize the pair currently worked on .ToList(); RandomUtilities.ShuffleList(remainingDimensionIndexes, _nextInt); List<int> setDimensionIndexes = new List<int>(currentDimensionsToCover); foreach (int dimensionIndex in remainingDimensionIndexes) { ReadOnlyCollection<int> allowedValueIndexes = UsePartialConstraintChecker ? partialConstraintChecker.GetAllowedValueIndexesForDimension(dimensionIndex, setDimensionIndexes, currentCombination) : Enumerable.Range(0, currentCombination.GetDimensionSize(dimensionIndex)).ToList().AsReadOnly(); if (allowedValueIndexes.Count == 0) { break; } currentCombination[dimensionIndex] = allowedValueIndexes[_nextInt(allowedValueIndexes.Count)]; setDimensionIndexes.Add(dimensionIndex); } if (setDimensionIndexes.Count < dimensionValues.Count) { // Couldn't set all dimension values, try again (or quit) continue; } currentVector = currentCombination.GenerateVector(); if (partialConstraintChecker != null || IsValidVector(currentVector)) { coveredCombinations.AddCoveredPairwiseCombinations(currentCombination, dimensionIndexGenerator); yield return currentVector; break; // Out of the MAXTRIES loop } } } } }
/// <summary> /// Explores the input (sub-)space. Each invocation may return a different set. /// </summary> /// <returns> /// A (reasonably-sized) stream of vectors/values from the (sub-)space. /// </returns> public override IEnumerable <Vector> Explore() { if (TargetMatrix.Dimensions.Count == 0) { // No dimensions to explore, then yield one empty vector. yield return(new Vector()); yield break; } ReadOnlyCollection <DimensionWithValues> dimensionValues = GetAllDimensionValues(); if (dimensionValues.Any(dim => dim.Values.Count == 0)) { yield break; // One of the dimensions is empty } if (dimensionValues.Count < _order) { // This is really non-sensical to ask for an n-wise strategy for a matrix with less than n dimensions // but I'd rather return a good default than throw. So I'll just cheat and do an exhaustive strategy instead ExhaustiveCombinatorialStrategy exhaustiveStrategy = new ExhaustiveCombinatorialStrategy(this); foreach (Vector v in exhaustiveStrategy.Explore()) { yield return(v); } yield break; } CoveredPairwiseCombinations coveredCombinations = new CoveredPairwiseCombinations(); DimensionValueIndexCombination currentCombination = new DimensionValueIndexCombination(dimensionValues); DimensionIndexCombinationGenerator dimensionIndexGenerator = CreateDimensionIndexCombinationGenerator(dimensionValues); Vector currentVector = currentCombination.GenerateVector(); if (IsValidVector(currentVector)) { coveredCombinations.AddCoveredPairwiseCombinations(currentCombination, dimensionIndexGenerator); yield return(currentVector); } PartialVectorConstraintChecker partialConstraintChecker = UsePartialConstraintChecker ? new PartialVectorConstraintChecker(dimensionValues, Constraints) : null; foreach (ReadOnlyCollection <int> currentDimensionsToCover in dimensionIndexGenerator.Generate()) { // Initialize the selection of values in the newly selected pairwise combination for (int i = 0; i < currentDimensionsToCover.Count; i++) { currentCombination[currentDimensionsToCover[i]] = 0; } while (true) { bool selectionSucceeded = SelectNextValuesForCurrentDimensionCombination(currentCombination, currentDimensionsToCover); if (!selectionSucceeded) { // We exhausted all combinations of values for the current pairwise combination // select the next pairwise combination break; } if (coveredCombinations.IsCombinationCovered(currentDimensionsToCover, currentCombination)) { continue; } if (partialConstraintChecker != null && !partialConstraintChecker.IsValidForApplicableConstraints(currentCombination, currentDimensionsToCover)) { // This combination is forbidden by constraints - carry on continue; } // Randomize other values, try at most MAXTRIES since we might hit invalid combinations for (int i = 0; i < MAXTRIES; i++) { List <int> remainingDimensionIndexes = Enumerable.Range(0, dimensionValues.Count) .Where(di => !currentDimensionsToCover.Contains(di)) // Don't randomize the pair currently worked on .ToList(); RandomUtilities.ShuffleList(remainingDimensionIndexes, _nextInt); List <int> setDimensionIndexes = new List <int>(currentDimensionsToCover); foreach (int dimensionIndex in remainingDimensionIndexes) { ReadOnlyCollection <int> allowedValueIndexes = UsePartialConstraintChecker ? partialConstraintChecker.GetAllowedValueIndexesForDimension(dimensionIndex, setDimensionIndexes, currentCombination) : Enumerable.Range(0, currentCombination.GetDimensionSize(dimensionIndex)).ToList().AsReadOnly(); if (allowedValueIndexes.Count == 0) { break; } currentCombination[dimensionIndex] = allowedValueIndexes[_nextInt(allowedValueIndexes.Count)]; setDimensionIndexes.Add(dimensionIndex); } if (setDimensionIndexes.Count < dimensionValues.Count) { // Couldn't set all dimension values, try again (or quit) continue; } currentVector = currentCombination.GenerateVector(); if (partialConstraintChecker != null || IsValidVector(currentVector)) { coveredCombinations.AddCoveredPairwiseCombinations(currentCombination, dimensionIndexGenerator); yield return(currentVector); break; // Out of the MAXTRIES loop } } } } }
private IEnumerable<TestRow> Explore(TestConfigurationMatrix matrix, TestMatrixExplorationKind explorationKind, TestRunStrategy testRunStrategy) { List<KeyValuePair<Dimension, IExplorationStrategy>> testShellDimensionsWithStrategies = new List<KeyValuePair<Dimension, IExplorationStrategy>>(); List<IConstraint> testShellContraints = new List<IConstraint>(); Dictionary<string, TestDimension> testDimensionsToExpand = new Dictionary<string, TestDimension>(); foreach (var testDimension in matrix.Dimensions) { testDimensionsToExpand.Add(testDimension.Name, testDimension); } // Now override any dimensions for the run Strategy if (testRunStrategy != null) { foreach (var testDimension in testRunStrategy.OverrideDimensions) { testDimensionsToExpand[testDimension.Name] = testDimension; } } // Add test matrix combinations this.GetFlattenDimensionsWithConstraints(testDimensionsToExpand.Values, testShellDimensionsWithStrategies, testShellContraints); // Create test dimension for the platforms var platformDimension = new Dimension<string>("Platform"); var platformExplorationStrategy = new ExhaustiveIEnumerableStrategy<string>(matrix.TestAssemblies.Select(ta => ta.PlatformType.ToString())); testShellDimensionsWithStrategies.Add(new KeyValuePair<Dimension, IExplorationStrategy>(platformDimension, platformExplorationStrategy)); CombinatorialStrategy testConfigurationExplorationStrategy = null; Matrix testShellMatrix = new Matrix(matrix.Name, testShellDimensionsWithStrategies.Select(pair => pair.Key).ToArray()); if (explorationKind == TestMatrixExplorationKind.Exhaustive) { testConfigurationExplorationStrategy = new ExhaustiveCombinatorialStrategy(testShellMatrix, testShellContraints); } else { testConfigurationExplorationStrategy = new PairwiseStrategy(testShellMatrix, this.RandomNumberGenerator.Next, testShellContraints); } foreach (var ds in testShellDimensionsWithStrategies) { testConfigurationExplorationStrategy.SetDimensionStrategy(ds.Key, ds.Value); } List<TestRow> testRows = new List<TestRow>(); foreach (var vector in testConfigurationExplorationStrategy.Explore()) { Dictionary<string, string> rowValues = new Dictionary<string, string>(); foreach (var testShellDimensionWithStrategy in testShellDimensionsWithStrategies) { rowValues.Add(testShellDimensionWithStrategy.Key.Name, (string)vector.GetValue(testShellDimensionWithStrategy.Key)); } testRows.Add(new TestRow(rowValues)); } return testRows; }