/// <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
						}
					}
				}
			}
		}