# Path: concept_formation/utils.py
# def mean(values):
#     """
#     Computes the mean of a list of values.
# 
#     This is primarily included to reduce dependency on external math libraries
#     like numpy in the core algorithm.
# 
#     :param values: a list of numbers
#     :type values: list
#     :return: the mean of the list of values
#     :rtype: float
# 
#     >>> mean([600, 470, 170, 430, 300])
#     394.0
#     """
#     if len(values) <= 0:
#         raise ValueError("Length of list must be greater than 0.")
# 
#     return float(sum(values))/len(values)
# 
# Path: concept_formation/utils.py
# def isNumber(n):
#     """
#     Check if a value is a number that should be handled differently than
#     nominals.
#     """
#     return (not isinstance(n, bool) and isinstance(n, Number)) and not isnan(n)
# 
# Path: concept_formation/structure_mapper.py
# class StructureMapper(Preprocessor):
#     """
#     Structure maps an instance that has been appropriately preprocessed (i.e.,
#     standardized apart, flattened, subcomponent processed, and lists processed
#     out). Transform renames the instance based on this structure mapping, and
#     return the renamed instance.
# 
#     :param base: A concept to structure map the instance to
#     :type base: TrestleNode
#     :param gensym: a function that returns unique object names (str) on each
#         call
#     :type gensym: function
#     :return: A flattened and mapped copy of the instance
#     :rtype: instance
#     """
#     def __init__(self, base):
#         self.base = base
#         self.mapping = None
#         self.reverse_mapping = None
# 
#     def get_mapping(self):
#         """
#         Returns the currently established mapping.
# 
#         :return: The current mapping.
#         :rtype: dict
#         """
#         return {self.reverse_mapping[o]: o for o in self.reverse_mapping}
# 
#     def transform(self, target, initial_mapping=None):
#         """
#         Transforms a provided target (either an instance or an av_counts table
#         from a CobwebNode or Cobweb3Node).
# 
#         :param target: An instance or av_counts table to rename to bring into
#             alignment with the provided base.
#         :type target: instance or av_counts table (from CobwebNode or
#             Cobweb3Node).
#         :return: The renamed instance or av_counts table
#         :rtype: instance or av_counts table
#         """
#         self.mapping = flat_match(target, self.base, initial_mapping)
#         self.reverse_mapping = {self.mapping[o]: o for o in self.mapping}
#         return rename_flat(target, self.mapping)
# 
#     def undo_transform(self, target):
#         """
#         Takes a transformed target and reverses the structure mapping using the
#         mapping discovered by transform.
# 
#         :param target: A previously renamed instance or av_counts table to
#             reverse the structure mapping on.
#         :type target: previously structure mapped instance or av_counts table
#             (from CobwebNode or Cobweb3Node).
#         :return: An instance or concept av_counts table with original object
#             names
#         :rtype: dict
#         """
#         if self.reverse_mapping is None:
#             raise Exception("Must transform before undoing transform")
#         return rename_flat(target, self.reverse_mapping)


from random import shuffle
from re import search
from concept_formation.utils import mean
from concept_formation.utils import isNumber
from concept_formation.structure_mapper import StructureMapper
        :class:`Cobweb3Tree <concept_formation.cobweb3.Cobweb3Tree>`, or
        :class:`TrestleTree <concept_formation.trestle.TrestleTree>`
    :param instance: An instance to use query the tree with
    :type instance: {a1:v1, a2:v2, ...}
    :param attr: A target instance attribute to evaluate probability on
    :type attr: :ref:`Attribute<attributes>`
    :param val: The target value of the given attr
    :type val: A :ref:`Nominal<val-nom>` or :ref:`Numeric<val-num>` value.
    :returns: The probabily of the given instance attribute value in the given
        tree
    :rtype: float
    """
    if attr in instance:
        instance = {a: instance[a] for a in instance if not a == attr}
    concept = tree.categorize(instance)

    if isinstance(val, dict):
        raise Exception(
            "Probability cannot be estimated on component attributes!")
        structure_mapper = StructureMapper(concept)
        temp_instance = structure_mapper.transform(instance)
        mapping = structure_mapper.get_mapping()

        # temp_instance = flatten_json(instance)
        # mapping = flat_match(concept, temp_instance)
        # temp_instance = rename_flat(temp_instance, mapping)

        probs = [concept.probability(sub_attr, temp_instance[sub_attr])
                 for sub_attr in temp_instance
                 if search(r'^' + mapping[attr], sub_attr)]

# Path: concept_formation/utils.py
# def mean(values):
#     """
#     Computes the mean of a list of values.
# 
#     This is primarily included to reduce dependency on external math libraries
#     like numpy in the core algorithm.
# 
#     :param values: a list of numbers
#     :type values: list
#     :return: the mean of the list of values
#     :rtype: float
# 
#     >>> mean([600, 470, 170, 430, 300])
#     394.0
#     """
#     if len(values) <= 0:
#         raise ValueError("Length of list must be greater than 0.")
# 
#     return float(sum(values))/len(values)
# 
# Path: concept_formation/utils.py
# def isNumber(n):
#     """
#     Check if a value is a number that should be handled differently than
#     nominals.
#     """
#     return (not isinstance(n, bool) and isinstance(n, Number)) and not isnan(n)
# 
# Path: concept_formation/structure_mapper.py
# class StructureMapper(Preprocessor):
#     """
#     Structure maps an instance that has been appropriately preprocessed (i.e.,
#     standardized apart, flattened, subcomponent processed, and lists processed
#     out). Transform renames the instance based on this structure mapping, and
#     return the renamed instance.
# 
#     :param base: A concept to structure map the instance to
#     :type base: TrestleNode
#     :param gensym: a function that returns unique object names (str) on each
#         call
#     :type gensym: function
#     :return: A flattened and mapped copy of the instance
#     :rtype: instance
#     """
#     def __init__(self, base):
#         self.base = base
#         self.mapping = None
#         self.reverse_mapping = None
# 
#     def get_mapping(self):
#         """
#         Returns the currently established mapping.
# 
#         :return: The current mapping.
#         :rtype: dict
#         """
#         return {self.reverse_mapping[o]: o for o in self.reverse_mapping}
# 
#     def transform(self, target, initial_mapping=None):
#         """
#         Transforms a provided target (either an instance or an av_counts table
#         from a CobwebNode or Cobweb3Node).
# 
#         :param target: An instance or av_counts table to rename to bring into
#             alignment with the provided base.
#         :type target: instance or av_counts table (from CobwebNode or
#             Cobweb3Node).
#         :return: The renamed instance or av_counts table
#         :rtype: instance or av_counts table
#         """
#         self.mapping = flat_match(target, self.base, initial_mapping)
#         self.reverse_mapping = {self.mapping[o]: o for o in self.mapping}
#         return rename_flat(target, self.mapping)
# 
#     def undo_transform(self, target):
#         """
#         Takes a transformed target and reverses the structure mapping using the
#         mapping discovered by transform.
# 
#         :param target: A previously renamed instance or av_counts table to
#             reverse the structure mapping on.
#         :type target: previously structure mapped instance or av_counts table
#             (from CobwebNode or Cobweb3Node).
#         :return: An instance or concept av_counts table with original object
#             names
#         :rtype: dict
#         """
#         if self.reverse_mapping is None:
#             raise Exception("Must transform before undoing transform")
#         return rename_flat(target, self.reverse_mapping)


# Path: concept_formation/evaluation.py
from random import shuffle
from re import search
from concept_formation.utils import mean
from concept_formation.utils import isNumber
from concept_formation.structure_mapper import StructureMapper

        :class:`Cobweb3Tree <concept_formation.cobweb3.Cobweb3Tree>`, or
        :class:`TrestleTree <concept_formation.trestle.TrestleTree>`
    :param instance: An instance to use query the tree with
    :type instance: {a1:v1, a2:v2, ...}
    :param attr: A target instance attribute to evaluate probability on
    :type attr: :ref:`Attribute<attributes>`
    :param val: The target value of the given attr
    :type val: A :ref:`Nominal<val-nom>` or :ref:`Numeric<val-num>` value.
    :returns: The probabily of the given instance attribute value in the given
        tree
    :rtype: float
    """
    if attr in instance:
        instance = {a: instance[a] for a in instance if not a == attr}
    concept = tree.categorize(instance)

    if isinstance(val, dict):
        raise Exception(
            "Probability cannot be estimated on component attributes!")
        structure_mapper = StructureMapper(concept)
        temp_instance = structure_mapper.transform(instance)
        mapping = structure_mapper.get_mapping()

        # temp_instance = flatten_json(instance)
        # mapping = flat_match(concept, temp_instance)
        # temp_instance = rename_flat(temp_instance, mapping)

        probs = [concept.probability(sub_attr, temp_instance[sub_attr])
                 for sub_attr in temp_instance
                 if search(r'^' + mapping[attr], sub_attr)]

        return mean(probs)