public FunctionalDependency GetMinimalFD(FunctionalDependency fd) { var det = fd.Determinants; if (det.Count == 1) { return(fd); } var refClosure = GetClosure(det); foreach (var attr in det) { var testdets = det.GetExcepted(attr); if (refClosure.SetEquals(GetClosure(testdets))) { return(GetMinimalFD(fd.Dependent.DependsOn(testdets))); } } return(fd.Dependent.DependsOn(det)); }
/// <summary> /// Step 2 /// </summary> public static Tuple <bool, HashSet <HashSet <Attribute> > > IsAttributeSuperfluous(Relation reference, HashSet <Relation> relations, Relation target, Attribute attr) { var none = Tuple.Create <bool, HashSet <HashSet <Attribute> > >(false, null); if (!target.Attributes.Contains(attr)) { throw new ArgumentException("target relation does not contain requested attribute"); } if (!relations.Contains(target)) { throw new ArgumentException("relation set does not contain target relation"); } var Ki = new HashSet <HashSet <Attribute> >(target.FDs.Select(fd => fd.Determinants), HashSet <Attribute> .CreateSetComparer()); if (Ki.Count == 1 && Ki.Single().SetEquals(target.Attributes)) { return(none); } var Ki_prime = new HashSet <HashSet <Attribute> >(Ki.Where(x => !x.Contains(attr)), HashSet <Attribute> .CreateSetComparer()); if (!Ki_prime.Any()) { return(none); } var Gi = new HashSet <FunctionalDependency>(); foreach (var K in Ki) { Gi.UnionWith(FunctionalDependency.Decompose(K, target.Attributes.GetExceptedMany(K))); } var Gi_R = new Relation(Relation.GetAttributeSet(Gi), Gi); var Gi_prime = new HashSet <FunctionalDependency>(); foreach (var G in relations.Where(r => r != target)) { Gi_prime.UnionWith(G.FDs); } var exceptAttr = target.FDs.Where(fd => !fd.Determinants.Contains(attr)); var Ai_prime = target.Attributes.GetExcepted(attr); foreach (var fd in exceptAttr) { var K = fd.Determinants; Gi_prime.UnionWith(FunctionalDependency.Decompose(K, Ai_prime.GetExceptedMany(K))); } var Gi_primeR = new Relation(Relation.GetAttributeSet(Gi_prime), Gi_prime); // check restorability foreach (var K in Ki_prime) { if (!Gi_primeR.GetClosure(K).Contains(attr)) { return(none); } } // B is restorable, check non-essentiality foreach (var K in Ki.Except(Ki_prime)) { var M = Gi_primeR.GetClosure(K); if (target.Attributes.SetEquals(M)) { return(Tuple.Create(true, Ki_prime)); } var M_test = new HashSet <Attribute>(M); M_test.IntersectWith(target.Attributes); M_test.Remove(attr); // M_test = (M intersect Ai) - B if (!reference.GetClosure(M_test).IsSupersetOf(target.Attributes)) { return(none); } // add key of Ri in M_test to Ki_prime // only consider attributes found in FDs, not "dangling" attributes var attrCover = new HashSet <Attribute>(); foreach (var k in Ki_prime) { attrCover.UnionWith(k); } attrCover.IntersectWith(M_test); //Ki_prime.Clear(); Ki_prime.Add(target.MinimizeAttributeSet(attrCover)); } return(Tuple.Create(true, Ki_prime)); }