'''
Main learner class.

@author: anze.vavpetic@ijs.si
'''
from collections import defaultdict
from itertools import combinations

from ..core import UnaryPredicate, Rule, Example
from ..core.settings import logger
from ..stats.significance import is_redundant
from ..stats.scorefunctions import interesting

from .learner import Learner


class OptimalLearner(Learner):
    '''
    Finds the optimal top-k rules.
    '''
    def __init__(self, kb, n=None, min_sup=1, sim=1, depth=4, target=None,
                 use_negations=False, optimal_subclass=True):
        Learner.__init__(self, kb, n=n, min_sup=min_sup, sim=sim, depth=depth,
                         target=target, use_negations=use_negations)

    def induce(self):
        '''
        Induces rules for the given knowledge base.
        '''
        kb = self.kb
        has_min_sup = lambda pred: kb.get_members(pred).count() >= self.min_sup
        all_predicates = filter(has_min_sup, kb.predicates)
        rules = []
        for depth in range(1, self.depth+1):
            for attrs in combinations(all_predicates, depth):
                rule = Rule(kb, predicates=self._labels_to_predicates(attrs),
                            target=self.target)
                rules.append(rule)
        rules = sorted(rules, key=lambda r: r.score, reverse=True)
        return rules[:self.n]

    def _labels_to_predicates(self, labels):
        predicates = []
        producer_pred = None
        for label in labels:
            members = self.kb.get_members(label)
            predicates.append(UnaryPredicate(label, members, self.kb,
                                             producer_pred=producer_pred,
                                             custom_var_name='X'))
            producer_pred = predicates[-1]
        return predicates
