<commit_before>"""
Types used on a per-build basis.
"""

__author__ = "<NAME>"
__date__ = "2012-11-09"

__all__ = [
    "Context",
    "resolve",
]


from _compat import *

from collections import defaultdict
from collections import deque
from functools import partial
from itertools import product
from itertools import starmap

from mybuild.core import *
from mybuild.pgraph import *
from mybuild.solver import solve

from util.itertools import pop_iter

import logging
logger = logging.getLogger(__name__)


class Context(object):
    """docstring for Context"""

    def __init__(self):
        super(Context, self).__init__()
        self._domains = dict()  # {module: domain}, domain is optuple of sets
        self._instantiation_queue = deque()

        self.pgraph = ContextPgraph(self)
        self.instance_nodes = list()

    def domain_for(self, module):
        try:
            domain = self._domains[module]
        except KeyError:
            domain = self._domains[module] = \
                    module._opmake(set(optype._values)
                                   for optype in module._optypes)
            self.post_product(domain)

        return domain

    def post(self, optuple, origin=None):
        self._instantiation_queue.append((optuple, origin))

    def post_product(self, iterables_optuple, origin=None):
        for optuple in map(iterables_optuple._make,
                           product(*iterables_optuple)):
            self.post(optuple, origin)

    def post_discover(self, optuple, origin=None):
        domain = self.domain_for(optuple._module)

        for value, domain_to_extend in optuple._zipwith(domain):
            if value in domain_to_extend:
                continue

            domain_to_extend.add(value)

            self.post_product(optuple._make(option_domain
                    if option_domain is not domain_to_extend else (value,)
                    for option_domain in domain), origin)

    def instantiate(self, optuple, origin=None):
        g = self.pgraph
        node = g.node_for(optuple)

        logger.debug("new %s (posted by %s)", optuple, origin)
        try:
            instance = optuple._instantiate_module()

        except InstanceError as error:
            logger.debug("    %s inviable: %s", optuple, error)

            node.error = error
            g.new_const(False, node,
                        why=why_inviable_instance_is_disabled)

        else:
            node.instance = instance

            for constraint, condition in instance._constraints:
                self.post_discover(constraint, instance)
                if condition:
                    node.implies(g.node_for(constraint),
                                 why=why_instance_implies_its_constraints)

        self.instance_nodes.append(node)

        return node

    def discover_all(self, initial_optuple):
        self.post_discover(initial_optuple)

        for optuple, origin in pop_iter(self._instantiation_queue,
                                        pop_meth='popleft'):
            self.instantiate(optuple, origin)

    def init_pgraph_domains(self):
        g = self.pgraph

        for module, domain in iteritems(self._domains):
            atom_for_module = partial(g.atom_for, module)
            module_atom = atom_for_module()

            for option, values in domain._iterpairs():
                atom_for_option = partial(atom_for_module, option)

                option_node = AtMostOne(g, map(atom_for_option, values),
                        why_one_operand_zero_implies_others_identity=
                            why_option_can_have_at_most_one_value,
                        why_identity_implies_all_operands_identity=
                            why_disabled_option_cannot_have_a_value,
                        why_all_operands_identity_implies_identity=
                            why_option_with_no_value_must_be_disabled)

                module_atom.equivalent(option_node,
                        why_becauseof=why_option_implies_module,
                        why_therefore=why_module_implies_option)

    def resolve(self, initial_module):
        optuple = initial_module()

        self.discover_all(optuple)
        self.init_pgraph_domains()

        solution = solve(self.pgraph, {self.pgraph.node_for(optuple): True})

        return [node.instance
                for node in self.instance_nodes if solution[node]]


class ContextPgraph(Pgraph):

    def __init__(self, context):
        super(ContextPgraph, self).__init__()
        self.context = context

    def atom_for(self, module, option=None, value=Ellipsis):
        if option is not None:
            return self.new_node(OptionValueAtom, module, option, value)
        else:
            return self.new_node(ModuleAtom, module)

    def node_for(self, mslice):
        # TODO should accept arbitrary expr as well.
        return self.new_node(OptupleNode, mslice())


@ContextPgraph.node_type
class ModuleAtom(Atom):
<commit_msg>context: resolve returns module-to-instance mapping instead of instance list<commit_after>"""
Types used on a per-build basis.
"""

__author__ = "<NAME>"
__date__ = "2012-11-09"

__all__ = [
    "Context",
    "resolve",
]


from _compat import *

from collections import defaultdict
from collections import deque
from functools import partial
from itertools import product
from itertools import starmap

from mybuild.core import *
from mybuild.pgraph import *
from mybuild.solver import solve

from util.itertools import pop_iter

import logging
logger = logging.getLogger(__name__)


class Context(object):
    """docstring for Context"""

    def __init__(self):
        super(Context, self).__init__()
        self._domains = dict()  # {module: domain}, domain is optuple of sets
        self._instantiation_queue = deque()

        self.pgraph = ContextPgraph(self)
        self.instance_nodes = list()

    def domain_for(self, module):
        try:
            domain = self._domains[module]
        except KeyError:
            domain = self._domains[module] = \
                    module._opmake(set(optype._values)
                                   for optype in module._optypes)
            self.post_product(domain)

        return domain

    def post(self, optuple, origin=None):
        self._instantiation_queue.append((optuple, origin))

    def post_product(self, iterables_optuple, origin=None):
        for optuple in map(iterables_optuple._make,
                           product(*iterables_optuple)):
            self.post(optuple, origin)

    def post_discover(self, optuple, origin=None):
        domain = self.domain_for(optuple._module)

        for value, domain_to_extend in optuple._zipwith(domain):
            if value in domain_to_extend:
                continue

            domain_to_extend.add(value)

            self.post_product(optuple._make(option_domain
                    if option_domain is not domain_to_extend else (value,)
                    for option_domain in domain), origin)

    def instantiate(self, optuple, origin=None):
        g = self.pgraph
        node = g.node_for(optuple)

        logger.debug("new %s (posted by %s)", optuple, origin)
        try:
            instance = optuple._instantiate_module()

        except InstanceError as error:
            logger.debug("    %s inviable: %s", optuple, error)

            node.error = error
            g.new_const(False, node,
                        why=why_inviable_instance_is_disabled)

        else:
            node.instance = instance

            for constraint, condition in instance._constraints:
                self.post_discover(constraint, instance)
                if condition:
                    node.implies(g.node_for(constraint),
                                 why=why_instance_implies_its_constraints)

        self.instance_nodes.append(node)

        return node

    def discover_all(self, initial_optuple):
        self.post_discover(initial_optuple)

        for optuple, origin in pop_iter(self._instantiation_queue,
                                        pop_meth='popleft'):
            self.instantiate(optuple, origin)

    def init_pgraph_domains(self):
        g = self.pgraph

        for module, domain in iteritems(self._domains):
            atom_for_module = partial(g.atom_for, module)
            module_atom = atom_for_module()

            for option, values in domain._iterpairs():
                atom_for_option = partial(atom_for_module, option)

                option_node = AtMostOne(g, map(atom_for_option, values),
                        why_one_operand_zero_implies_others_identity=
                            why_option_can_have_at_most_one_value,
                        why_identity_implies_all_operands_identity=
                            why_disabled_option_cannot_have_a_value,
                        why_all_operands_identity_implies_identity=
                            why_option_with_no_value_must_be_disabled)

                module_atom.equivalent(option_node,
                        why_becauseof=why_option_implies_module,
                        why_therefore=why_module_implies_option)

    def resolve(self, initial_module):
        optuple = initial_module()

        self.discover_all(optuple)
        self.init_pgraph_domains()

        solution = solve(self.pgraph, {self.pgraph.node_for(optuple): True})

        instances = [node.instance
                     for node in self.instance_nodes if solution[node]]
        instance_map = dict((type(instance), instance)
                            for instance in instances)
        return instance_map


class ContextPgraph(Pgraph):

    def __init__(self, context):
        super(ContextPgraph, self).__init__()
        self.context = context

    def atom_for(self, module, option=None, value=Ellipsis):
        if option is not None:
            return self.new_node(OptionValueAtom, module, option, value)
        else:
            return self.new_node(ModuleAtom, module)

    def node_for(self, mslice):
        # TODO should accept arbitrary expr as well.
        return self.new_node(OptupleNode, mslice())


@ContextPgraph.node_type
class ModuleAtom(Atom):

{'fraction_non_alphanumeric': 0.07687041564792176, 'fraction_numerical': 0.0015647921760391199, 'mean_word_length': 2.1688875116207003, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6094123', 'n_tokens_mistral': 2903, 'n_tokens_neox': 2753, 'n_words': 625}