# Path: concept_formation/utils.py
# def weighted_choice(choices):
#     """
#     Given a list of tuples [(val, weight),...(val, weight)], return a randomly
#     chosen value where the choice frequency is proportional to the choice
#     weight divided by the sum of all weights. Note, weights must be greater
#     than or equal to 0.
# 
#     :param choices: A list of tuples
#     :type choices: [(val, weight),...(val, weight)]
#     :return: A choice sampled from the list according to the weightings
#     :rtype: val
# 
#     >>> from random import seed
#     >>> seed(1234)
#     >>> options = [('a',.25),('b',.12),('c',.46),('d',.07)]
#     >>> weighted_choice(options)
#     'd'
#     >>> weighted_choice(options)
#     'c'
#     >>> weighted_choice(options)
#     'a'
# 
#     .. seealso::
#         :meth:`CobwebNode.sample <concept_formation.cobweb.CobwebNode.sample>`
#     """
#     total = sum(w for c, w in choices)
#     r = uniform(0, total)
#     upto = 0
#     for c, w in choices:
#         if w < 0:
#             raise ValueError('All weights must be greater than or equal to 0.')
#         if upto + w > r:
#             return c
#         upto += w
#     raise ValueError("Choices cannot be an empty list")
# 
# Path: concept_formation/utils.py
# def most_likely_choice(choices):
#     """
#     Given a list of tuples [(val, weight),...(val, weight)], returns the value
#     with the highest weight. Ties are randomly broken.
# 
#     >>> options = [('a',.25),('b',.12),('c',.46),('d',.07)]
#     >>> most_likely_choice(options)
#     'c'
#     >>> most_likely_choice(options)
#     'c'
#     >>> most_likely_choice(options)
#     'c'
# 
#     :param choices: A list of tuples
#     :type choices: [(val, weight),...(val, weight)]
#     :return: the val with the hightest weight
#     :rtype: val
#     """
#     if len(choices) == 0:
#         raise ValueError("Choices cannot be an empty list")
# 
#     vals = [w for _, w in choices if w < 0]
#     if len(vals) > 0:
#         raise ValueError('All weights must be greater than or equal to 0')
# 
#     updated_choices = [(prob, random(), val) for val, prob in choices]
#     return sorted(updated_choices, reverse=True)[0][2]


from random import shuffle
from random import random
from math import log
from concept_formation.utils import weighted_choice
from concept_formation.utils import most_likely_choice
            count = self.av_counts[attr][val]
            choices.append((val, count / self.count))
            val_count += count

        if allow_none:
            choices.append((None, ((self.count - val_count) / self.count)))

        return choices

    def predict(self, attr, choice_fn="most likely", allow_none=True):
        """
        Predict the value of an attribute, using the specified choice function
        (either the "most likely" value or a "sampled" value).

        :param attr: an attribute of an instance.
        :type attr: :ref:`Attribute<attributes>`
        :param choice_fn: a string specifying the choice function to use,
            either "most likely" or "sampled".
        :type choice_fn: a string
        :param allow_none: whether attributes not in the instance can be
            inferred to be missing. If False, then all attributes will be
            inferred with some value.
        :type allow_none: Boolean
        :return: The most likely value for the given attribute in the node's
                 probability table.
        :rtype: :ref:`Value<values>`
        """
        if choice_fn == "most likely" or choice_fn == "m":
            choose = most_likely_choice
        elif choice_fn == "sampled" or choice_fn == "s":

# Path: concept_formation/utils.py
# def weighted_choice(choices):
#     """
#     Given a list of tuples [(val, weight),...(val, weight)], return a randomly
#     chosen value where the choice frequency is proportional to the choice
#     weight divided by the sum of all weights. Note, weights must be greater
#     than or equal to 0.
# 
#     :param choices: A list of tuples
#     :type choices: [(val, weight),...(val, weight)]
#     :return: A choice sampled from the list according to the weightings
#     :rtype: val
# 
#     >>> from random import seed
#     >>> seed(1234)
#     >>> options = [('a',.25),('b',.12),('c',.46),('d',.07)]
#     >>> weighted_choice(options)
#     'd'
#     >>> weighted_choice(options)
#     'c'
#     >>> weighted_choice(options)
#     'a'
# 
#     .. seealso::
#         :meth:`CobwebNode.sample <concept_formation.cobweb.CobwebNode.sample>`
#     """
#     total = sum(w for c, w in choices)
#     r = uniform(0, total)
#     upto = 0
#     for c, w in choices:
#         if w < 0:
#             raise ValueError('All weights must be greater than or equal to 0.')
#         if upto + w > r:
#             return c
#         upto += w
#     raise ValueError("Choices cannot be an empty list")
# 
# Path: concept_formation/utils.py
# def most_likely_choice(choices):
#     """
#     Given a list of tuples [(val, weight),...(val, weight)], returns the value
#     with the highest weight. Ties are randomly broken.
# 
#     >>> options = [('a',.25),('b',.12),('c',.46),('d',.07)]
#     >>> most_likely_choice(options)
#     'c'
#     >>> most_likely_choice(options)
#     'c'
#     >>> most_likely_choice(options)
#     'c'
# 
#     :param choices: A list of tuples
#     :type choices: [(val, weight),...(val, weight)]
#     :return: the val with the hightest weight
#     :rtype: val
#     """
#     if len(choices) == 0:
#         raise ValueError("Choices cannot be an empty list")
# 
#     vals = [w for _, w in choices if w < 0]
#     if len(vals) > 0:
#         raise ValueError('All weights must be greater than or equal to 0')
# 
#     updated_choices = [(prob, random(), val) for val, prob in choices]
#     return sorted(updated_choices, reverse=True)[0][2]


# Path: concept_formation/cobweb.py
from random import shuffle
from random import random
from math import log
from concept_formation.utils import weighted_choice
from concept_formation.utils import most_likely_choice

            count = self.av_counts[attr][val]
            choices.append((val, count / self.count))
            val_count += count

        if allow_none:
            choices.append((None, ((self.count - val_count) / self.count)))

        return choices

    def predict(self, attr, choice_fn="most likely", allow_none=True):
        """
        Predict the value of an attribute, using the specified choice function
        (either the "most likely" value or a "sampled" value).

        :param attr: an attribute of an instance.
        :type attr: :ref:`Attribute<attributes>`
        :param choice_fn: a string specifying the choice function to use,
            either "most likely" or "sampled".
        :type choice_fn: a string
        :param allow_none: whether attributes not in the instance can be
            inferred to be missing. If False, then all attributes will be
            inferred with some value.
        :type allow_none: Boolean
        :return: The most likely value for the given attribute in the node's
                 probability table.
        :rtype: :ref:`Value<values>`
        """
        if choice_fn == "most likely" or choice_fn == "m":
            choose = most_likely_choice
        elif choice_fn == "sampled" or choice_fn == "s":

            choose = weighted_choice