public PatternMiningResult FilterRules(
            PatternMiningResult results,
            int minimumRuleSupport        = 500,
            double minimimRuleOccFraction = 0.7)
        {
            var filteredRulesGeohashCounts = new Dictionary <string, Dictionary <PatternRule, Dictionary <string, int> > >();
            var filteredRulesCounts        = new Dictionary <string, Dictionary <PatternRule, int> >();

            foreach (var domainToCounts in results.RulesGeohashCounts)
            {
                var domain = domainToCounts.Key;
                var domainRulesToGeohashCounts = domainToCounts.Value;
                var domainRulesCounts          = results.RulesCounts[domain];

                var filteredRulesToGeohashCounts = this.AddRetrieveDomainToRulesGeohashCounts(filteredRulesGeohashCounts, domain);
                var filteredRulesToCounts        = this.AddRetrieveDomainToRulesCounts(filteredRulesCounts, domain);

                foreach (var ruleToGeohashCounts in domainRulesToGeohashCounts)
                {
                    var rule          = ruleToGeohashCounts.Key;
                    var geohashCounts = ruleToGeohashCounts.Value;

                    var ruleTotalCount = domainRulesCounts[rule];

                    foreach (var geohashCount in geohashCounts)
                    {
                        var geohash = geohashCount.Key;
                        var count   = geohashCount.Value;

                        var occFraction = count / (1.0d * ruleTotalCount);

                        if (count >= minimumRuleSupport && occFraction >= minimimRuleOccFraction)
                        {
                            //Console.WriteLine($"{domain}\t{rule}\t{geohash}\t{count} / {ruleTotalCount} =\t{occFraction}");

                            filteredRulesToCounts[rule] = ruleTotalCount;

                            Dictionary <string, int> filteredGeohashCounts;

                            if (!filteredRulesToGeohashCounts.TryGetValue(rule, out filteredGeohashCounts))
                            {
                                filteredGeohashCounts = new Dictionary <string, int>();
                                filteredRulesToGeohashCounts[rule] = filteredGeohashCounts;
                            }

                            filteredGeohashCounts[geohash] = count;
                        }
                    }
                }
            }

            return(new PatternMiningResult()
            {
                RulesGeohashCounts = filteredRulesGeohashCounts,
                RulesCounts = filteredRulesCounts
            });
        }
        public Dictionary <string, Dictionary <PatternRule, PatternMiningCoordinates> > ReduceRules(PatternMiningResult results)
        {
            var reducedRules = new Dictionary <string, Dictionary <PatternRule, PatternMiningCoordinates> >();

            foreach (var domainToRulesEntry in results.RulesGeohashCounts)
            {
                var domain = domainToRulesEntry.Key;
                var ruleCountsForDomain           = results.RulesCounts[domain];
                var rulesToGeohashCountsForDomain = domainToRulesEntry.Value;

                Dictionary <PatternRule, PatternMiningCoordinates> rulesForDomain;

                if (!reducedRules.TryGetValue(domain, out rulesForDomain))
                {
                    rulesForDomain       = new Dictionary <PatternRule, PatternMiningCoordinates>();
                    reducedRules[domain] = rulesForDomain;
                }

                foreach (var ruleEntry in rulesToGeohashCountsForDomain)
                {
                    var rule           = ruleEntry.Key;
                    var ruleTotalCount = ruleCountsForDomain[rule];
                    var geohashCounts  = ruleEntry.Value;

                    rulesForDomain[rule] = FindBestCoordinates(geohashCounts, ruleTotalCount);
                }
            }

            return(reducedRules);
        }