Пример #1
0
        private void GetPrimes()
        {
            SufficientCandidateKeys.Clear();
            _prime = new BitArray(Keys.Count);
            var leftBits = new BitArray(Keys.Count);

            foreach (var key in Left)
            {
                _prime[key]   = true;
                leftBits[key] = true;
            }
            foreach (var key in Right)
            {
                _prime[key] = false;
            }
            foreach (var key in Middle)
            {
                _prime[key] = false;
            }
            var currentCover = Reachability(leftBits);
            var candidates   = new List <int>(Middle);

            candidates.RemoveAll(key => currentCover[key]);
            if (candidates.Count == 0)
            {
                SufficientCandidateKeys.Add(leftBits);
                return;
            }
            var graph = new Graph(Keys.Count);

            foreach (var dependency in DependencyList)
            {
                var str = dependency.Item1.ToBitString();
                if (str.Count(c => c == '1') != 1)
                {
                    continue;
                }
                var index = str.IndexOf('1');
                if (!candidates.Contains(index))
                {
                    continue;
                }
                for (var i = 0; i < Keys.Count; i++)
                {
                    if (dependency.Item2[i] && candidates.Contains(i))
                    {
                        graph.AddEdge(index, i);
                    }
                }
            }
            graph.GetSccs();
            var sccs = new List <List <int> >();

            for (var i = 0; i < candidates.Count; i++)
            {
                sccs.Add(new List <int>());
                sccs.Last().Add(candidates[i]);
                for (var j = i + 1; j < candidates.Count; j++)
                {
                    if (graph.Scc[candidates[i]] != graph.Scc[candidates[j]])
                    {
                        continue;
                    }
                    sccs.Last().Add(candidates[j]);
                    candidates.RemoveAt(j);
                    j--;
                }
            }
            for (var i = 0; i < candidates.Count; i++)
            {
                if (sccs[i].Any(candidate => DependencyList.Any(dependency => dependency.Item2[candidate] && Keys.Any(key => dependency.Item1[key] && graph.Scc[key] != graph.Scc[candidate]))))
                {
                    continue;
                }
                leftBits[sccs[i][0]] = true;
                foreach (var key in sccs[i])
                {
                    _prime[key] = true;
                    Left.Add(key);
                    Middle.Remove(key);
                }
                sccs.RemoveAt(i);
                candidates.RemoveAt(i);
                i--;
            }
            currentCover = Reachability(leftBits);
            for (var i = 0; i < candidates.Count; i++)
            {
                if (!currentCover[candidates[i]])
                {
                    continue;
                }
                foreach (var key in sccs[i])
                {
                    _prime[key] = false;
                }
                sccs.RemoveAt(i);
                candidates.RemoveAt(i);
                i--;
            }
            if (candidates.Count == 0)
            {
                SufficientCandidateKeys.Add(leftBits);
                return;
            }
            // I claim by this line, the number of candidates can't be more than 16; given that the number of attributes isn't more than 4069, but who knows!
            if (candidates.Count > 20)
            {
                throw new ConstraintException("Too many attributes!");
            }
            var foundSets = new List <int>();

            for (var i = 1; i < (1 << candidates.Count); i++)
            {
                var currentSet = new BitArray(leftBits);
                var newSet     = false;
                for (var j = 0; j < candidates.Count; j++)
                {
                    if ((i & (1 << j)) != 0)
                    {
                        currentSet[candidates[j]] = true;
                        newSet |= !_prime[candidates[j]];
                    }
                }
                if (foundSets.Any(set => (i & set) == set))
                {
                    i += i & -i;
                    i--;
                    continue;
                }
                if (Reachability(currentSet).ToBitString().Contains('0'))
                {
                    continue;
                }
                foundSets.Add(i);
                SufficientCandidateKeys.Add(currentSet);
                for (var j = 0; j < candidates.Count; j++)
                {
                    if ((i & (1 << j)) != 0 && !_prime[candidates[j]])
                    {
                        foreach (var k in sccs[j])
                        {
                            _prime[k] = true;
                        }
                    }
                }
                i += i & -i;
                i--;
            }
        }