/// <summary>
                /// Set top level and non top level concept types after
                /// the optimal permutation state has been determined
                /// </summary>
                /// <param name="permutationState"><see cref="ChainPermutationState"/> containing the top level and non top level ObjectTypes</param>
                public void SetConceptTypes(ChainPermutationState permutationState)
                {
                    Debug.Assert(myConceptTypes == null);
                    int count = permutationState.TopLevelCount + permutationState.NonTopLevelCount;

                    ConceptTypeEntry[] entries = new ConceptTypeEntry[count];
                    if (count != 0)
                    {
                        int index = 0;
                        foreach (KeyValuePair <ObjectType, ObjectTypeStates> pair in permutationState.EnumerateStates(ObjectTypeStates.TopLevelInPermutation | ObjectTypeStates.NonTopLevelInPermutation))
                        {
                            entries[index] = new ConceptTypeEntry(pair.Key, 0 != (pair.Value & ObjectTypeStates.TopLevelInPermutation));
                            ++index;
                        }
                        Debug.Assert(index == count);
                        if (count > 1)
                        {
                            Array.Sort <ConceptTypeEntry>(entries, ConceptTypeEntry.Comparer);
                        }
                    }
                    myConceptTypes = entries;
                }
			private static void FindSmallestPermutationsInTermsOfConceptTypes(Chain chain, ChainPermutationState permutationState)
		{
			permutationState.BeginChainEvaluation(chain);

			IList<Permutation> smallestPermutationsInTermsOfConceptTypes = chain.SmallestPermutationsInTermsOfConceptTypes;

			int minTopLevelConceptTypesCount = int.MaxValue;
			int minNonTopLevelConceptTypesCount = int.MaxValue;

			foreach (Permutation permutation in chain.PossiblePermutations)
			{
				bool isNotOptimalPermutation = false;
				permutationState.BeginPermutation(permutation);

				foreach (ObjectType objectType in chain.ObjectTypes)
				{
					ObjectTypeStates startingState = permutationState.GetState(objectType);
					if (0 != (startingState & (ObjectTypeStates.PredecidedMustHaveConceptType | ObjectTypeStates.PermutationMustHaveConceptType)))
					{
						if (0 != (startingState & (ObjectTypeStates.PredecidedMustNotHaveTopLevelConceptType | ObjectTypeStates.PermutationMustNotHaveTopLevelConceptType)))
						{
							if (permutationState.SetNonTopLevel(objectType) &&
								(permutationState.TopLevelCount == minTopLevelConceptTypesCount) &&
								(permutationState.NonTopLevelCount > minNonTopLevelConceptTypesCount))
							{
								// We now have more non-top-level concept types than the minimum, and the same number of top-level concept types as the minimum, so throw this permutation out.
								isNotOptimalPermutation = true;
								break;
							}
						}
						else
						{
							if (permutationState.SetTopLevel(objectType) &&
								(permutationState.TopLevelCount > minTopLevelConceptTypesCount))
							{
								// We now have more top-level concept types than the minimum, so throw this permutation out.
								isNotOptimalPermutation = true;
								break;
							}
						}
					}
				}

				if (isNotOptimalPermutation)
				{
					// This isn't an optimal permutation, so go on to the next one.
					continue;
				}

				int topLevelCount = permutationState.TopLevelCount;
				int nonTopLevelCount = permutationState.NonTopLevelCount;
				Debug.Assert(topLevelCount <= minTopLevelConceptTypesCount, "Permutations with greater than the minimum number of top-level concept types should have been rejected inline.");

				if (topLevelCount < minTopLevelConceptTypesCount)
				{
					// We have a new minimum number of top-level concept types (and hence a new minimum number of non-top-level concept types as well).
					minTopLevelConceptTypesCount = topLevelCount;
					minNonTopLevelConceptTypesCount = nonTopLevelCount;
					smallestPermutationsInTermsOfConceptTypes.Clear();
				}
				else
				{
					// We have the same number of top-level concept types as the minimum, so we need to check the number of non-top-level concept types.
					if (nonTopLevelCount > minNonTopLevelConceptTypesCount)
					{
						// This isn't an optimal permutation, so go on to the next one.
						continue;
					}
					else if (nonTopLevelCount < minNonTopLevelConceptTypesCount)
					{
						// We have a new minimum number of non-top-level concept type.
						minNonTopLevelConceptTypesCount = nonTopLevelCount;
						smallestPermutationsInTermsOfConceptTypes.Clear();
					}
				}
				permutation.SetConceptTypes(permutationState);
				smallestPermutationsInTermsOfConceptTypes.Add(permutation);
			}
		}
			private void PermuteFactTypeMappings()
			{
				// UNDONE: We should consider whether we can determine what object types will collapse earlier in the process, which would allow us to
				// potentially eliminate multiple permutations that have the same result. (Rationale: When an object type is collapsed, it doesn't matter
				// whether the mappings away from it are shallow or deep; they both result in the same output.)

				int largestChainCount;
				FactTypeMappingDictionary allDecidedMappings = myDecidedFactTypeMappings;
				// Break up the chains of contiguous one-to-one fact types
				FactTypeChainer chainer = new FactTypeChainer(myPredecidedManyToOneFactTypeMappings, myPredecidedOneToOneFactTypeMappings, myUndecidedOneToOneFactTypeMappings);

				// If some chains end up at a size we cannot process, then running
				// the chainer can move some mappings from undecided to predecided.
				// We pass in the decided mappings so that we do not lose track
				// of these entries.
				largestChainCount = chainer.Run(allDecidedMappings);

				// Perform one-time pass of top-level types for the decided mappings
				//PrecalculateDecidedConceptTypes();

				// This is used in PermuteFactTypeMappings(). We allocate it once, here, for permformance reasons.
				FactTypeMappingList newlyDecidedFactTypeMappings = new FactTypeMappingList(largestChainCount);

				// This is used to prevent deep mappings of an object type in two directions.
				Dictionary<ObjectType, object> deeplyMappedObjectTypes = new Dictionary<ObjectType, object>(largestChainCount);
				ChainPermutationState permutationStateHelper = new ChainPermutationState();
				// Used to eliminate deep mappings towards simple identifiers
				Dictionary<ObjectType, bool> nonPreferredFunctionalObjectTypesCache = new Dictionary<ObjectType, bool>();

				// Loop through each chain, calculating the permutations.
				foreach (Chain chain in chainer.Chains)
				{
					// Find the object types that we already know have deep mappings away from them.
					foreach (FactTypeMapping decidedMapping in chain.PredecidedOneToOneFactTypeMappings)
					{
						if (decidedMapping.MappingDepth == MappingDepth.Deep)
						{
							deeplyMappedObjectTypes[decidedMapping.FromObjectType] = null;
						}
					}

					PermuteFactTypeMappings(chain.PossiblePermutations, chain.UndecidedOneToOneFactTypeMappings, newlyDecidedFactTypeMappings, deeplyMappedObjectTypes, 0);
					EliminateInvalidPermutations(chain, nonPreferredFunctionalObjectTypesCache);
					FindSmallestPermutationsInTermsOfConceptTypes(chain, permutationStateHelper);
#if FALSE
					// UNDONE: See notes on EliminatePermutationsWithIdenticalResults
					EliminatePermutationsWithIdenticalResults(chain);
#endif // FALSE

					// Add each mapping from the optimal permutation to the "global" set of decided mappings.
					foreach (FactTypeMapping optimalMapping in ChooseOptimalPermutation(chain).Mappings)
					{
						allDecidedMappings.Add(optimalMapping.FactType, optimalMapping);
					}

					// Clear the set of object types that have some deep mapping away from them (they will be different for the next chain).
					deeplyMappedObjectTypes.Clear();
				}
			}