public Chain() { myObjectTypes = new List <ObjectType>(); myPredecidedManyToOneFactTypeMappings = new FactTypeMappingList(); myPredecidedOneToOneFactTypeMappings = new FactTypeMappingList(); myUndecidedOneToOneFactTypeMappings = new FactTypeMappingListList(); myPossiblePermutations = new List <Permutation>(); mySmallestPermutationsInTermsOfConceptTypes = new List <Permutation>(); }
/// <summary> /// Determines the obvious fact type mappings, and all other potential mappings. /// </summary> /// <param name="modelFactTypes">The <see cref="FactType"/> objects of the model</param> /// <param name="decidedManyToOneFactTypeMappings">The decided many-to-one <see cref="FactTypeMapping"/> objects.</param> /// <param name="decidedOneToOneFactTypeMappings">The decided one-to-one <see cref="FactTypeMapping"/> objects.</param> /// <param name="undecidedOneToOneFactTypeMappings">The undecided <see cref="FactTypeMapping"/> possibilities.</param> private void PerformInitialFactTypeMappings(LinkedElementCollection<FactType> modelFactTypes, FactTypeMappingDictionary decidedManyToOneFactTypeMappings, FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { // For each fact type in the model... foreach (FactType factType in modelFactTypes) { if (ShouldIgnoreFactType(factType)) { continue; } SubtypeFact subtypeFact = factType as SubtypeFact; // If it's a subtype relation... MandatoryConstraint mandatory; if (subtypeFact != null) { Role subtypeRole = subtypeFact.SubtypeRole; Role supertypeRole = subtypeFact.SupertypeRole; mandatory = supertypeRole.SingleRoleAlethicMandatoryConstraint; // Note that the only way to get a mandatory on the supertype role is with an implied mandatory, verified explicitly below // Map deeply toward the supertype. FactTypeMapping factTypeMapping = new FactTypeMapping( subtypeFact, subtypeRole, supertypeRole, FactTypeMappingFlags.Subtype | FactTypeMappingFlags.DeepMapping | FactTypeMappingFlags.FromRoleMandatory | ((mandatory != null && mandatory.IsImplied) ? FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory : FactTypeMappingFlags.None) | (subtypeRole.RolePlayer.IsValueType ? FactTypeMappingFlags.FromValueType | FactTypeMappingFlags.TowardsValueType : FactTypeMappingFlags.None)); decidedOneToOneFactTypeMappings.Add(subtypeFact, factTypeMapping); } else { LinkedElementCollection<RoleBase> roles = factType.RoleCollection; Debug.Assert(roles.Count == 2 && (factType.Objectification == null || factType.UnaryRole != null), "Non-binarized fact types should have been filtered out already."); Role firstRole = roles[0].Role; Role secondRole = roles[1].Role; ObjectType firstRolePlayer = firstRole.RolePlayer; ObjectType secondRolePlayer = secondRole.RolePlayer; UniquenessConstraint firstRoleUniquenessConstraint = (UniquenessConstraint)firstRole.SingleRoleAlethicUniquenessConstraint; UniquenessConstraint secondRoleUniquenessConstraint = (UniquenessConstraint)secondRole.SingleRoleAlethicUniquenessConstraint; bool firstRolePlayerIsValueType = firstRolePlayer.IsValueType; bool secondRolePlayerIsValueType = secondRolePlayer.IsValueType; bool firstRoleIsUnique = (firstRoleUniquenessConstraint != null); bool secondRoleIsUnique = (secondRoleUniquenessConstraint != null); bool firstRoleIsMandatory = null != (mandatory = firstRole.SingleRoleAlethicMandatoryConstraint); bool firstRoleIsImplicitlyMandatory = firstRoleIsMandatory && mandatory.IsImplied; bool firstRoleIsExplicitlyMandatory = firstRoleIsMandatory && !firstRoleIsImplicitlyMandatory; bool secondRoleIsMandatory = null != (mandatory = secondRole.SingleRoleAlethicMandatoryConstraint); bool secondRoleIsImplicitlyMandatory = secondRoleIsMandatory && mandatory.IsImplied; bool secondRoleIsExplicitlyMandatory = secondRoleIsMandatory && !secondRoleIsImplicitlyMandatory; // We don't need to worry about shallow mappings towards preferred identifiers on many-to-ones, since the preferred // identifier pattern ensures that these cases will always map towards the object type being identified anyway. const int FIRST_SECOND_SHALLOW = 1; const int FIRST_SECOND_DEEP = 2; const int SECOND_FIRST_SHALLOW = 4; const int SECOND_FIRST_DEEP = 8; int possibilityBits = 0; bool manyToOne = false; // If only firstRole is unique... if (firstRoleIsUnique && !secondRoleIsUnique) { // Shallow map toward firstRolePlayer. possibilityBits |= SECOND_FIRST_SHALLOW; manyToOne = true; } else if (!firstRoleIsUnique && secondRoleIsUnique) // ...only secondRole is unique... { // Shallow map toward secondRolePlayer. possibilityBits |= FIRST_SECOND_SHALLOW; manyToOne = true; } else if (firstRoleIsUnique && secondRoleIsUnique) // ...both roles are unique... { // If this is a ring fact type... if (firstRolePlayer == secondRolePlayer) { // If only firstRole is mandatory... if (firstRoleIsExplicitlyMandatory && !secondRoleIsExplicitlyMandatory) { // Shallow map toward firstRolePlayer (mandatory role player). possibilityBits |= FIRST_SECOND_SHALLOW; } else if (!firstRoleIsExplicitlyMandatory && secondRoleIsExplicitlyMandatory) // ...only secondRole is mandatory... { // Shallow map toward secondRolePlayer (mandatory role player). possibilityBits |= SECOND_FIRST_SHALLOW; } else // ...otherwise... { // Shallow map toward firstRolePlayer. possibilityBits |= FIRST_SECOND_SHALLOW; } } else // ...not a ring fact type... { // These are used to make sure that we never shallowly map towards a preferred identifier. bool firstRoleIsUniqueAndPreferred = firstRoleIsUnique && firstRoleUniquenessConstraint.IsPreferred; bool secondRoleIsUniqueAndPreferred = secondRoleIsUnique && secondRoleUniquenessConstraint.IsPreferred; // If neither role is mandatory... if (!firstRoleIsExplicitlyMandatory && !secondRoleIsExplicitlyMandatory) { // If firstRole is not preferred... if (!firstRoleIsUniqueAndPreferred) { // Shallow map toward firstRolePlayer. possibilityBits |= SECOND_FIRST_SHALLOW; } // If secondRole is not preferred... if (!secondRoleIsUniqueAndPreferred) { // Shallow map toward secondRolePlayer. possibilityBits |= FIRST_SECOND_SHALLOW; } } else if (firstRoleIsExplicitlyMandatory && !secondRoleIsExplicitlyMandatory) // ...only firstRole is mandatory... { // Note that the first role cannot be be preferred if the second role is not mandatory // Shallow map toward firstRolePlayer. possibilityBits |= SECOND_FIRST_SHALLOW; #if FALSE // UNDONE: This is a much deeper check for 1-1 patterns off of mandatory constraints. Both this and // the current much quicker check are meant to limit permutation checks on patterns where numerous // 1-1 fact types reference the same optional role player. Both of these systems are extremely fragile // to one of the uses of the value being made mandatory, in which case this loop does not apply. // We need to find a quicker mechanism for determining when we should allow an absorption towards // a fully optional object type, or some other check to eliminate extremely long chains (these can // easily consume all memory on a machine). bool allowMappingTowardsOptionalRole = true; if (null != (mandatory = secondRolePlayer.ImpliedMandatoryConstraint)) { if (!(secondRoleIsUniqueAndPreferred && factType.ImpliedByObjectification != null)) { foreach (Role testRole in mandatory.RoleCollection) { if (testRole != secondRole && !ShouldIgnoreFactType((testRole.Proxy ?? (RoleBase)testRole).FactType)) { Role oppositeRole; if (testRole.SingleRoleAlethicUniquenessConstraint != null && null != (oppositeRole = testRole.OppositeRoleAlwaysResolveProxy as Role) && null != oppositeRole.SingleRoleAlethicUniquenessConstraint && null != (mandatory = oppositeRole.SingleRoleAlethicMandatoryConstraint) && !mandatory.IsImplied) { // If there are multiple 1-1 mappings towards an object type with // an implied mandatory, then don't consider any mappings towards // this entity. allowMappingTowardsOptionalRole = false; break; } } } } } if (allowMappingTowardsOptionalRole) #endif // FALSE if (null == secondRolePlayer.ImpliedMandatoryConstraint || ((secondRoleIsUniqueAndPreferred && !secondRolePlayerIsValueType) || factType.ImpliedByObjectification != null)) { // If secondRole is not preferred... if (!secondRoleIsUniqueAndPreferred) { // Shallow map toward secondRolePlayer. possibilityBits |= FIRST_SECOND_SHALLOW; } // Deep map toward secondRolePlayer. possibilityBits |= FIRST_SECOND_DEEP; } } else if (!firstRoleIsExplicitlyMandatory && secondRoleIsExplicitlyMandatory) // ...only secondRole is mandatory... { // Note that the second role cannot be preferred if the first role is not mandatory // Shallow map toward secondRolePlayer. possibilityBits |= FIRST_SECOND_SHALLOW; #if FALSE // UNDONE: See comments above, duplicate code switching first and second bool allowMappingTowardsOptionalRole = true; if (null != (mandatory = firstRolePlayer.ImpliedMandatoryConstraint)) { if (!(firstRoleIsUniqueAndPreferred && factType.ImpliedByObjectification != null)) { foreach (Role testRole in mandatory.RoleCollection) { if (testRole != firstRole && !ShouldIgnoreFactType((testRole.Proxy ?? (RoleBase)testRole).FactType)) { Role oppositeRole; if (testRole.SingleRoleAlethicUniquenessConstraint != null && null != (oppositeRole = testRole.OppositeRoleAlwaysResolveProxy as Role) && null != oppositeRole.SingleRoleAlethicUniquenessConstraint && null != (mandatory = oppositeRole.SingleRoleAlethicMandatoryConstraint) && !mandatory.IsImplied) { // If there are multiple 1-1 mappings towards an object type with // an implied mandatory, then don't consider any mappings towards // this entity. allowMappingTowardsOptionalRole = false; break; } } } } } if (allowMappingTowardsOptionalRole) #endif // FALSE if (null == firstRolePlayer.ImpliedMandatoryConstraint || ((firstRoleIsUniqueAndPreferred && !firstRolePlayerIsValueType) || factType.ImpliedByObjectification != null)) { // If firstRole is not preferred... if (!firstRoleIsUniqueAndPreferred) { // Shallow map toward firstRolePlayer. possibilityBits |= SECOND_FIRST_SHALLOW; } // Deep map toward firstRolePlayer. possibilityBits |= SECOND_FIRST_DEEP; } } else // ...both roles are mandatory... { // If firstRole is not preferred... if (!firstRoleIsUniqueAndPreferred) { // Shallow map toward firstRolePlayer. possibilityBits |= SECOND_FIRST_SHALLOW; } // If secondRole is not preferred... if (!secondRoleIsUniqueAndPreferred) { // Shallow map toward secondRolePlayer. possibilityBits |= FIRST_SECOND_SHALLOW; } // Possible deep map toward firstRolePlayer and toward secondRolePlayer possibilityBits |= FIRST_SECOND_DEEP | SECOND_FIRST_DEEP; } } } Debug.Assert(possibilityBits != 0); switch (possibilityBits) { case FIRST_SECOND_SHALLOW: (manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, firstRole, secondRole, GetFlags(false, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory))); break; case SECOND_FIRST_SHALLOW: (manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, secondRole, firstRole, GetFlags(false, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory))); break; case FIRST_SECOND_DEEP: (manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, firstRole, secondRole, GetFlags(true, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory))); break; case SECOND_FIRST_DEEP: (manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, secondRole, firstRole, GetFlags(true, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory))); break; default: { // UNDONE: I don't see any reason to use a heavy-weight list structure here. The // same information could be stored in an UndecidedFactTypeMapping structure that // uses a bit field mechanism similar to this block of code. This would allow us // to store the factType/firstRole/secondRole once and interpret the contents based // on a single bitfield. In the meantime, keep the list as small as possible. int countBits = possibilityBits; int count = 0; while (countBits != 0) { if (0 != (countBits & 1)) { ++count; } countBits >>= 1; } FactTypeMappingList potentialMappingList = new FactTypeMappingList(count); count = -1; if (0 != (possibilityBits & FIRST_SECOND_SHALLOW)) { potentialMappingList.Add(new FactTypeMapping(factType, firstRole, secondRole, GetFlags(false, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory))); } if (0 != (possibilityBits & SECOND_FIRST_SHALLOW)) { potentialMappingList.Add(new FactTypeMapping(factType, secondRole, firstRole, GetFlags(false, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory))); } if (0 != (possibilityBits & FIRST_SECOND_DEEP)) { potentialMappingList.Add(new FactTypeMapping(factType, firstRole, secondRole, GetFlags(true, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory))); } if (0 != (possibilityBits & SECOND_FIRST_DEEP)) { potentialMappingList.Add(new FactTypeMapping(factType, secondRole, firstRole, GetFlags(true, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory))); } undecidedOneToOneFactTypeMappings.Add(factType, potentialMappingList); break; } } } } }
/// <summary> /// Permutes the <see cref="FactTypeMapping"/>s, recursively. /// </summary> /// <param name="permutations">The collection containing <see cref="Permutation"/>s that have already been calculated, and to which newly calculated <see cref="Permutation"/>s are added.</param> /// <param name="undecidedMappings">The list of potential <see cref="FactTypeMapping"/>s for each <see cref="FactType"/> that need to be permuted.</param> /// <param name="decidedMappings">The <see cref="FactTypeMapping"/>s that have already been decided for this branch of the permutation. Should initially be empty.</param> /// <param name="deeplyMappedObjectTypes"><see cref="ObjectType"/>s that already have some deep <see cref="FactTypeMapping"/> away from them.</param> /// <param name="currentPosition">The index into <paramref name="undecidedMappings"/> that should be processed.</param> private static void PermuteFactTypeMappings(IList<Permutation> permutations, FactTypeMappingListList undecidedMappings, FactTypeMappingList decidedMappings, Dictionary<ObjectType, object> deeplyMappedObjectTypes, int currentPosition) { int nextPosition = currentPosition + 1; bool isLastUndecided = (nextPosition == undecidedMappings.Count); foreach (FactTypeMapping potentialMapping in undecidedMappings[currentPosition]) { if (potentialMapping.MappingDepth == MappingDepth.Deep && deeplyMappedObjectTypes.ContainsKey(potentialMapping.FromObjectType)) { // We already have a deep mapping away from this object type, so we can skip this potential mapping (which would result in an illegal permutation). continue; } // Put this potential mapping onto the stack of decided mappings. decidedMappings.Add(potentialMapping); if (isLastUndecided) { // This is the end of the list of undecided fact types, so we can create a permutation. permutations.Add(new Permutation(new FactTypeMappingList(decidedMappings))); } else { if (potentialMapping.MappingDepth == MappingDepth.Deep) { // This is a deep mapping, so add the from object type to the set of deeply mapped object types. deeplyMappedObjectTypes[potentialMapping.FromObjectType] = null; } // Go on to the potential mappings for the next undecided fact type. PermuteFactTypeMappings(permutations, undecidedMappings, decidedMappings, deeplyMappedObjectTypes, nextPosition); if (potentialMapping.MappingDepth == MappingDepth.Deep) { // Remove the from object type from the set of deeply mapped object types. deeplyMappedObjectTypes.Remove(potentialMapping.FromObjectType); } } // Pop this potential mapping off the stack of decided mappings so that we can go on to the next potential mapping. decidedMappings.RemoveAt(decidedMappings.Count - 1); } }
private static FactTypeMapping FindDeepMappingAwayFromObjectType(ObjectType objectType, FactTypeMappingList predecidedOneToOneFactTypeMappings, FactTypeMappingList permutationFactTypeMappings) { // UNDONE: Figure out a way we can do this off of PlayedRoles instead, which should be faster. foreach (FactTypeMapping mapping in predecidedOneToOneFactTypeMappings) { if (mapping.MappingDepth == MappingDepth.Deep && mapping.FromObjectType == objectType) { return mapping; } } foreach (FactTypeMapping mapping in permutationFactTypeMappings) { if (mapping.MappingDepth == MappingDepth.Deep && mapping.FromObjectType == objectType) { return mapping; } } return null; }
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(); } }
private static bool IsBlockedDeepMapping(FactTypeMappingList mappings, int currentMappingIndex, Dictionary<ObjectType, bool> nonPreferredFuntionalObjectTypes) { FactTypeMapping mapping = mappings[currentMappingIndex]; ObjectType towards; if (mapping.MappingDepth == MappingDepth.Deep && !ObjectTypePlaysNonIdentifierFunctionalRoles((towards = mapping.TowardsObjectType), nonPreferredFuntionalObjectTypes)) { int mappingsCount = mappings.Count; int j = 1; for (; j < mappingsCount; ++j) { int testIndex = (j + currentMappingIndex) % mappingsCount; FactTypeMapping testMapping = mappings[testIndex]; if (testMapping.MappingDepth == MappingDepth.Deep && testMapping.FromObjectType == towards && !IsBlockedDeepMapping(mappings, testIndex, nonPreferredFuntionalObjectTypes)) { break; } } if (j == mappingsCount) { return true; } } return false; }
/// <summary> /// If the number of undecided elements is unreasonably high, /// then apply incrementally more stringent requirements for /// deciding fact type mappings until we have a reasonable number. /// </summary> public void EnsureReasonablePermutations(FactTypeMappingListDictionary allUndecidedMappings, FactTypeMappingDictionary allPredecidedMappings, FactTypeMappingDictionary allDecidedMappings) { FactTypeMappingListList undecidedMappings = myUndecidedOneToOneFactTypeMappings; double maxPermutations = CalculateMaxNumberOfPermutations(undecidedMappings); if (maxPermutations > MaxReasonablePermutations) { int undecidedMappingCount = undecidedMappings.Count; Predicate <FactTypeMapping>[] reductionConditions = ReductionConditions; if (reductionConditions == null) { // Note that there is intentionally a lot of duplication in // these routines. An earlier design attempted to call previous // conditions along with later ones, but this resulted in a much // more complicated algorithm and multiple calls. The algorithm // was simplified in exchange for making these condition routines // more complicated. reductionConditions = new Predicate <FactTypeMapping>[] { delegate(FactTypeMapping mapping) { // If the fact type has a single non-mandatory value type // then do not map towards the value type. FactTypeMappingFlags mappingFlags = mapping.Flags; if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType)) { if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory)) { return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory)); } return(true); } return(false); }, delegate(FactTypeMapping mapping) { // If the fact type has an unbalanced mandatory and is not a subtype, // then map towards the mandatory. FactTypeMappingFlags mappingFlags = mapping.Flags; if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) && 0 == (mappingFlags & FactTypeMappingFlags.Subtype) && FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory))) { return(true); } // Duplicate previous ValueType check if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType)) { if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory)) { return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory)); } return(true); } return(false); }, delegate(FactTypeMapping mapping) { // Map away from a preferred identifier. This is not a cumulative test, and is ignored for later conditions. FactTypeMappingFlags mappingFlags = mapping.Flags; if (0 == (mappingFlags & FactTypeMappingFlags.FromPreferredIdentifier)) { return(true); } // Duplicate unbalanced ValueType and unbalanced mandatory checks if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) && 0 == (mappingFlags & FactTypeMappingFlags.Subtype) && FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory))) { return(true); } if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType)) { if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory)) { return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory)); } return(true); } return(false); }, delegate(FactTypeMapping mapping) { // Prefer a shallow mapping. FactTypeMappingFlags mappingFlags = mapping.Flags; if (0 != (mappingFlags & FactTypeMappingFlags.DeepMapping)) { return(true); } // Duplicate unbalanced ValueType and unbalanced mandatory checks if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) && 0 == (mappingFlags & FactTypeMappingFlags.Subtype) && FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory))) { return(true); } if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType)) { if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory)) { return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory)); } return(true); } return(false); }, delegate(FactTypeMapping mapping) { // If we have too many permutations then just map towards the first role. // Yes, this is completely arbitrary, but getting anywhere past item 2 on // this list will be extremely rarely and represents truly pathological cases. // Perform previous flag-based checks first. FactTypeMappingFlags mappingFlags = mapping.Flags; if (0 != (mappingFlags & FactTypeMappingFlags.DeepMapping)) { return(true); } if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) && 0 == (mappingFlags & FactTypeMappingFlags.Subtype) && FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory))) { return(true); } if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType)) { if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory)) { return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory)); } return(true); } Role role = mapping.TowardsRole; return(0 != mapping.FactType.RoleCollection.IndexOf((RoleBase)role.Proxy ?? role)); }, }; ReductionConditions = reductionConditions; } FactTypeMappingList decidedMappings = myPredecidedOneToOneFactTypeMappings; for (int maxReduction = 0; maxReduction < reductionConditions.Length; ++maxReduction) { for (int undecidedMappingIndex = undecidedMappingCount - 1; undecidedMappingIndex >= 0; --undecidedMappingIndex) { FactTypeMappingList testMappings = undecidedMappings[undecidedMappingIndex]; int testMappingCount = testMappings.Count; // Note that the max length of this list is four (shallow and deep both directions) FactTypeMapping singleMapping = null; for (int i = 0; i < testMappingCount; ++i) { FactTypeMapping testMapping = testMappings[i]; if (!reductionConditions[maxReduction](testMapping)) { // This test mapping is not filtered, allow it if (singleMapping == null) { singleMapping = testMapping; } else { singleMapping = null; break; } } } if (singleMapping != null) { decidedMappings.Add(singleMapping); undecidedMappings.RemoveAt(undecidedMappingIndex); --undecidedMappingCount; maxPermutations /= testMappingCount; FactType factTypeKey = singleMapping.FactType; allUndecidedMappings.Remove(factTypeKey); allPredecidedMappings.Add(factTypeKey, singleMapping); allDecidedMappings.Add(factTypeKey, singleMapping); } } if (maxPermutations <= MaxReasonablePermutations) { break; } } } }
public Permutation(FactTypeMappingList mappings) { myMappings = mappings; }