Ejemplo n.º 1
0
class Simulated_annealing_learner:
    def __init__(self, seed, initial_t, data, annealer):
        self.randomizer = Randomizer(seed)
        self.annealer = annealer
        self.T = initial_t
        self.data = data
        # self.hyp = self.annealer.find_initial_hypthesis(data)
        self.hyp = self.annealer.initial_hypothesis()
        self.creation_time = datetime.datetime.now()

    def simulated_annealing(self, create_plots, positive_examples,
                            output_directory, threshold, alpha):
        assert (0 < alpha < 1) and (0 < threshold) and (self.T > 0)
        iter_counter = 0
        p = None
        if create_plots:
            # Initial hypothesis
            self.hyp.plot_transitions(
                'hyp_%d ; E_%s' %
                (iter_counter,
                 self.annealer.metric_calc(self.hyp, positive_examples)),
                output_directory)

        while self.T > threshold:
            iter_counter += 1
            info("# ITERATION COUNTER =", iter_counter)
            info("Current temperature:", self.T)
            H_tag = self.annealer.get_random_neighbor(self.hyp, self.data)
            delta = self.annealer.energy_difference_a_minus_b(
                H_tag, self.hyp, positive_examples)
            info("Delta =", delta)
            if delta < 0:
                p = 1
            else:
                p = math.exp(-delta / self.T)
            if p >= self.randomizer.get_prng().random():
                info("Changing hypothesis\n")
                self.hyp = H_tag
            else:
                info("Didn't change hypothesis\n")
            energy = self.annealer.metric_calc(self.hyp, positive_examples)
            if create_plots:
                self.hyp.plot_transitions(
                    'hyp_%d ; E_%s' % (iter_counter, energy), output_directory)
            self.T *= alpha
        info("CHOSEN HYPOTHESIS:\n", self.hyp)

        return self.hyp, positive_examples

    def logger(self, create_plots, positive_examples, output_directory,
               threshold, alpha):
        info("# APPLYING LEARNER ON THE FOLLOWING POSITIVE EXAMPLES: %s" %
             ','.join(positive_examples))
        info("\nInitial temperature:", self.T, ", Threshold:", threshold,
             ", Alpha:", alpha)
        info("\n# INITIAL HYPOTHESIS:\n", self.hyp)
        info("\n")
        return self.simulated_annealing(create_plots, positive_examples,
                                        output_directory, threshold, alpha)
Ejemplo n.º 2
0
class DFA_Annealer:
    def __init__(self, seed):
        self.randomizer = Randomizer(seed)

    def __flip_acceptance_of_random_state(self, dfa):
        randomly_chosen_state = self.randomizer.get_prng().choice(
            list(dfa.states - {'qF'}))
        new_transitions = deepcopy(dfa.transitions)
        if '#' in new_transitions[randomly_chosen_state]:
            new_transitions[randomly_chosen_state].pop('#')
        else:
            new_transitions[randomly_chosen_state]['#'] = 'qF'
        new_dfa = DFA(deepcopy(dfa.states), new_transitions, 'q0',
                      deepcopy(dfa.accepting))
        info(new_dfa)
        return new_dfa

    def initial_hypothesis(self):
        """
        Returns a DFA that accepts all strings
        """
        states = {'q0', 'qF'}
        transitions = {'q0': {'0': 'q0', '1': 'q0', '#': 'qF'}}
        initial_state = 'q0'
        accepting_states = {'qF'}
        return DFA(states, transitions, initial_state, accepting_states)

    @staticmethod
    def energy_difference_a_minus_b(dfa_a, dfa_b, positive_examples):
        metric_eval_a = DFA_Annealer.metric_calc(dfa_a, positive_examples)
        # info("Evaluation of suggested hypothesis =", metric_eval_a)
        metric_eval_b = DFA_Annealer.metric_calc(dfa_b, positive_examples)
        # info("Evaluation of current hypothesis =", metric_eval_b)
        return metric_eval_a - metric_eval_b

    def get_random_neighbor(self, dfa, positive_examples):
        """
        Chooses randomly a potential random neighbor and calls function try_option in order to check the validity of the chosen neighbor.
        If the random neighbor is not valid for some reason (as will be described in the try_option documantion),
        the function will re-choose a potential neighbor.
        Number of retries is limited to 20. Once a valid neighbor is found, it will be returned by the function.
        If by the end of 20 tries it doesn't find a valid neighbor, the current DFA is returned.
        """
        options = [
            self.__flip_acceptance_of_random_state, self.__remove_final_state,
            self.__switching_transitions, self.__add_final_state,
            self.__increase_accepting_from_left,
            self.__increase_accepting_from_right,
            self.__decrease_accepting_from_left,
            self.__decrease_accepting_from_right,
            self.__remove_transition_from_qn, self.__remove_self_transitions
        ]
        for i in range(20):  #Limited to 20 tries
            if i >= 1:
                info("Raffles another hypothesis.")
            chosen_option = self.randomizer.get_prng().choice(options)
            result_dfa = self.__try_option(dfa, positive_examples,
                                           chosen_option)
            if result_dfa is not None:
                result_dfa.positive_examples = dfa.positive_examples
                return result_dfa
        return dfa

    @staticmethod
    def metric_calc(dfa, positive_examples):
        len_g = len(dfa.encode())
        len_d_g = sum(
            dfa.encode_positive_example(string)
            for string in positive_examples)
        return len_g + len_d_g

    '''
    Functions for getting random neighbor
    '''

    def __add_final_state(self, dfa):
        """
        Returns a DFA with one more state than the given DFA, which will be the new final state.
        The acceptance of the new final state will be identical to the acceptance of the previous final state

        @param DFA: DFA with n states
        @return new_DFA: DFA with n+1 states
        """
        # finding final state of given DFA
        prev_final_state = "q" + str(len(dfa.states) - 2)
        # finding final state of new DFA
        new_final_state = "q" + str(len(dfa.states) - 1)
        # Building new DFA
        new_states = dfa.states | {new_final_state}  # Adding new final state
        new_transitions = deepcopy(dfa.transitions)
        if new_transitions['q0'].get('0') == 'q0':
            new_transitions[prev_final_state]['1'] = new_final_state
        else:
            new_transitions[prev_final_state]['0'] = new_final_state
        new_transitions[new_final_state] = {}
        new_transitions[new_final_state]['0'] = new_final_state
        new_transitions[new_final_state]['1'] = new_final_state
        # new final state will agree with acceptance of prev final state
        if dfa.reaches_qf(prev_final_state):
            new_transitions[new_final_state]['#'] = 'qF'
        new_accepting = deepcopy(dfa.accepting)
        new_dfa = DFA(new_states, new_transitions, 'q0', new_accepting)
        info(new_dfa)
        return new_dfa

    def __remove_final_state(self, dfa):
        """
        Returns a DFA with one less state than the given DFA
        @param DFA: DFA with n states
        @return new_DFA: DFA with n-1 states
        """
        # Getting q_n of given DFA
        prev_final_state = "q" + str(len(dfa.states) - 2)
        # Removing q_n from states
        new_states = dfa.states - {prev_final_state}
        # Getting q_n of new DFA
        new_final_state = "q" + str(len(new_states) - 2)
        # Deleting transitions associated with q_n from transitions
        new_transitions = deepcopy(dfa.transitions)
        new_transitions[new_final_state]['0'] = new_final_state
        new_transitions[new_final_state]['1'] = new_final_state
        del new_transitions[prev_final_state]
        # Removing prev_final_state from accepting states of new dfa, if necessary
        new_accepting = dfa.accepting - {prev_final_state}

        new_dfa = DFA(new_states, new_transitions, 'q0', new_accepting)
        info(new_dfa)
        return new_dfa

    def __switching_transitions(delf, dfa):
        new_initial = 'q0'
        new_states = deepcopy(dfa.states)
        new_accepting = deepcopy(dfa.accepting)

        # Changing transitions
        def switch(edge_label):
            return '0' if edge_label == '1' else (
                '1' if edge_label == '0' else edge_label)

        new_transitions = {
            state: {
                switch(edge_label): dfa.transitions[state][edge_label]
                for edge_label in dfa.transitions[state]
            }
            for state in new_states - {'qF'}
        }
        new_dfa = DFA(new_states, new_transitions, new_initial, new_accepting)
        info(new_dfa)
        return new_dfa

    def __change_accepting_states(self, dfa, refer_state, size_change):
        """
        @param DFA: DFA with n states and x accpeting states
        @param refer_state: 'first_acc' for left-most accepting state or 'last_acc' for right-most accepting state.
        @param size_change: 'increase' or 'decrease'.
        @return new_DFA: DFA with change in accepting states per the other parameters.
        """
        accepting_ints = [
            int(state[1:]) for state in dfa.states if dfa.reaches_qf(state)
        ]
        new_transitions = deepcopy(dfa.transitions)
        if refer_state == 'first_acc':
            min_acc_index = min(accepting_ints)
            if size_change == 'decrease' or min_acc_index == 0:
                new_transitions['q' + str(min_acc_index)].pop('#')
            else:
                new_transitions['q' + str(min_acc_index - 1)]['#'] = 'qF'
        else:
            max_acc_index = max(accepting_ints)
            if size_change == 'decrease' or max_acc_index == len(
                    dfa.states) - 2:
                new_transitions['q' + str(max_acc_index)].pop('#')
            else:
                new_transitions['q' + str(max_acc_index + 1)]['#'] = 'qF'

        new_dfa = DFA(deepcopy(dfa.states), new_transitions, 'q0',
                      deepcopy(dfa.accepting))
        info(new_dfa)
        return new_dfa

    def __decrease_accepting_from_right(self, dfa):
        """
        @param DFA: DFA with n states and x accpeting states
        @return new_DFA: DFA with n and x+1 or x-1 accepting states, depanding on random choice
        """
        return self.__change_accepting_states(dfa, 'last_acc', 'decrease')

    def __decrease_accepting_from_left(self, dfa):
        """
        @param DFA: DFA with n states and x accpeting states
        @return new_DFA: DFA with n and x+1 or x-1 accepting states, depanding on random choice
        """
        return self.__change_accepting_states(dfa, 'first_acc', 'decrease')

    def __increase_accepting_from_right(self, dfa):
        """
        @param DFA: DFA with n states and x accpeting states
        @return new_DFA: DFA with n and x+1 or x-1 accepting states, depanding on random choice
        """
        return self.__change_accepting_states(dfa, 'last_acc', 'increase')

    def __increase_accepting_from_left(self, dfa):
        """
        @param DFA: DFA with n states and x accpeting states
        @return new_DFA: DFA with n and x+1 or x-1 accepting states, depanding on random choice
        """
        return self.__change_accepting_states(dfa, 'first_acc', 'increase')

    def __get_index_of_qn(self, dfa):
        return max(i for i in range(len(dfa.states))
                   if ('q%s' % i) in dfa.states)

    def __remove_self_transitions(self, dfa):
        new_transitions = {
            state: {
                edge_label: dfa.transitions[state][edge_label]
                for edge_label in dfa.transitions[state]
                if dfa.transitions[state][edge_label] != state
            }
            for state in dfa.transitions
        }
        new_dfa = DFA(deepcopy(dfa.states), new_transitions, 'q0',
                      deepcopy(dfa.accepting))
        info(new_dfa)
        return new_dfa

    def __remove_transition_from_qn(self, dfa):
        new_transitions = deepcopy(dfa.transitions)
        last_state_index = self.__get_index_of_qn(dfa)
        if last_state_index is not None:
            last_state = 'q%s' % last_state_index
            if all(symbol not in dfa.transitions[last_state]
                   for symbol in ['0', '1']):
                return deepcopy(dfa)
            if last_state_index == 0 or any(
                    symbol not in dfa.transitions[last_state]
                    for symbol in ['0', '1']):
                transition_to_remove = self.randomizer.get_prng().choice([
                    symbol for symbol in dfa.transitions[last_state]
                    if symbol != '#'
                ])
            else:
                prev_state = 'q%s' % (last_state_index - 1)
                transition_to_remove = '0' if new_transitions[prev_state].get(
                    '0') == last_state else '1'
            new_transitions[last_state].pop(transition_to_remove)

        new_dfa = DFA(deepcopy(dfa.states), new_transitions, 'q0',
                      deepcopy(dfa.accepting))
        info(new_dfa)
        return new_dfa

    def __try_option(self, dfa, positive_examples, chosen_option):
        """
        Checks whether a chosen neighbor is valid, i.e:
        1) Accepts all pairs in data
        2) Doesn't reduce a state from an only-state machine

        If one of the above doesn't hold, None is returned. Otherwise, the chosen neighbor is returned.
        """
        info("Random neighbor to be checked:", chosen_option.__name__)
        if len(dfa.states) <= 2 and chosen_option == self.__remove_final_state:
            info("Neigbor will cause dfa to have 0 states.")
            return None
        neighbor = chosen_option(dfa)
        # Check whether the neighbor dfa recognizes all couples in data
        # If not, return old dfa (i.e don't use neighbor). Otherwise, return neighbor
        for sample in positive_examples:
            if not neighbor.recognize(sample):
                info("Neighbor didn't recognize one of the pairs in data: %s" %
                     sample)
                return None
        info("Neighbor is valid.")
        return neighbor
class SingleSimulationRunner(object):
    def __init__(self, create_plots, seed):
        self.create_plots = create_plots
        self.randomizer = Randomizer(seed)

    def make_list_of_set_pairs_for_determiner_EXACTLY(
            self, ns, min_sample_for_each_n, max_sample_for_each_n,
            min_zeros_per_positive_example, max_zeros_per_positive_example):
        pairs = []
        for n in ns:
            pairs.extend([(set(
                range(n + self.randomizer.get_prng().randint(
                    min_zeros_per_positive_example,
                    max_zeros_per_positive_example))), set(range(n)))
                          for _ in range(self.randomizer.get_prng().randint(
                              min_sample_for_each_n, max_sample_for_each_n))])
        return pairs

    def simulate_EXACTLY(self, initial_temperature, threshold, alpha, ns,
                         min_sample_for_each_n, max_sample_for_each_n,
                         min_zeros_per_positive_example,
                         max_zeros_per_positive_example):
        data = self.make_list_of_set_pairs_for_determiner_EXACTLY(
            ns, min_sample_for_each_n, max_sample_for_each_n,
            min_zeros_per_positive_example, max_zeros_per_positive_example)
        return self.__simulate_with_data(
            'EXACTLY',
            dict(
                ns=ns,
                min_sample_for_each_n=min_sample_for_each_n,
                max_sample_for_each_n=max_sample_for_each_n,
                min_zeros_per_positive_example=min_zeros_per_positive_example,
                max_zeros_per_positive_example=max_zeros_per_positive_example),
            data, initial_temperature, threshold, alpha)

    def make_list_of_set_pairs_quantifier_ALL_OF_THE_EXACTLY(
            self, ns, min_sample_for_each_n, max_sample_for_each_n):
        pairs = []
        for n in ns:
            pairs.extend([(set(range(n)), set(range(n)))
                          for _ in range(self.randomizer.get_prng().randint(
                              min_sample_for_each_n, max_sample_for_each_n))])
        return pairs

    def simulate_ALL_OF_THE_EXACTLY(self, initial_temperature, threshold,
                                    alpha, ns, min_sample_for_each_n,
                                    max_sample_for_each_n):
        data = self.make_list_of_set_pairs_quantifier_ALL_OF_THE_EXACTLY(
            ns, min_sample_for_each_n, max_sample_for_each_n)
        return self.__simulate_with_data(
            'ALL_OF_THE_EXACTLY',
            dict(ns=ns,
                 min_sample_for_each_n=min_sample_for_each_n,
                 max_sample_for_each_n=max_sample_for_each_n), data,
            initial_temperature, threshold, alpha)

    def make_list_of_set_pairs_for_quantifier_all(self, min_set_size,
                                                  max_set_size,
                                                  number_of_pairs):
        lists = []
        for i in range(number_of_pairs):
            list_size = self.randomizer.get_prng().choice(
                range(min_set_size, max_set_size))
            lists.append((set(range(list_size)), set(range(list_size))))
        return lists

    def make_list_of_set_pairs_for_quantifier_none(self, min_set_size,
                                                   max_set_size,
                                                   number_of_pairs):
        lists = []
        for i in range(number_of_pairs):
            list_size = self.randomizer.get_prng().choice(
                range(min_set_size, max_set_size))
            lists.append((set(range(list_size)), set()))
        return lists

    def make_list_of_set_pairs_for_quantifier_between(
            self,
            at_least_ones,
            at_most_ones,
            min_size_of_universe,
            max_size_of_universe,
            number_of_positive_examples,
            add_examples_which_are_all_ones_of_these_lengths=[]):
        """
        Returns pairs, each of which will later be transformed into a binary string, which represents set membership.
        In each pair:
        1) First element is the universe: a set {0,...,M}, where M is a random number in [min_list_size, ..., max_list_size].
        2) Second element is a random subset {0,...,K}, where K is in [at_least, ..., at_most]. More precisely, K is in [at_least,..., M] if M < at_most.
    
        Thus generally speaking, the result is multiple instances of the generalized quantifier, each taken at random from a random size universe. Numeric example:
        at_least=3
        at_most=6
        min_list_size=20
        max_list_size=40
        number_of_lists=18
        We'll get 18 pairs. Example of one pair:
        (L1, L2) where
        L1 = {0, 1, 2, ..., 32}
        L2 = set(range(self.randomizer.get_prng().choice(range(3, min(7, 33))))) = set(range(self.randomizer.get_prng().choice(range(3, 7))) = set(range(22))
    
        :param at_least_ones:
        :param at_most_ones:
        :param min_size_of_universe:
        :param max_size_of_universe:
        :param number_of_positive_examples:
        :return:
        """
        if not all(at_least_ones <= length <= at_most_ones for length in
                   add_examples_which_are_all_ones_of_these_lengths):
            raise ValueError('Length to add is out of allowed range')
        positive_examples_as_pairs_of_sets = []
        for i in range(number_of_positive_examples):
            universe_size = self.randomizer.get_prng().choice(
                range(min_size_of_universe, max_size_of_universe))
            univese_set = set(range(universe_size))
            subset_of_universe = set(
                range(self.randomizer.get_prng().choice(
                    range(at_least_ones, min(at_most_ones + 1,
                                             universe_size)))))
            positive_examples_as_pairs_of_sets.append(
                (univese_set, subset_of_universe))
        positive_examples_as_pairs_of_sets.extend(
            (set(range(length)), set(range(length)))
            for length in add_examples_which_are_all_ones_of_these_lengths)
        return positive_examples_as_pairs_of_sets

    def simulate_whatever(self):
        DOGS = {'Rex', 'Spot', 'Bolt', 'Belka', 'Laika', 'Azit'}
        BROWN_ANIMALS = {'Belka', 'Spot', 'Azit', 'Mitzi'}
        SATELLITES = {
            'Yaogan', 'Ofeq_7', 'Ofeq_9', 'WorldView', 'Eros_B', 'Amos_5',
            'Glonass'
        }
        LOW_EARTH_ORBIT = {
            'Yaogan', 'Ofeq_7', 'Ofeq_9', 'WorldView', 'Eros_B', 'Hubble'
        }
        data = [(DOGS, BROWN_ANIMALS), (SATELLITES, LOW_EARTH_ORBIT)]

        DOGS = {'Rex', 'Spot', 'Bolt', 'Belka', 'Laika', 'Azit'}
        BROWN_ANIMALS = {
            'Rex', 'Spot', 'Bolt', 'Belka', 'Laika', 'Azit', 'IKEA table',
            'Humus'
        }
        SATELLITES = {'Yaogan', 'Ofeq_7', 'Ofeq_9', 'WorldView', 'Eros_B'}
        LOW_EARTH_ORBIT = {
            'Yaogan', 'Ofeq_7', 'Ofeq_9', 'WorldView', 'Eros_B', 'Hubble'
        }
        BOYS = {'Tom', 'John', 'Max', 'Mark', 'Barak', 'Guy', 'Ted', 'Joey'}
        HAPPY = {
            'Linda', 'Mary', 'Tom', 'John', 'Max', 'Mark', 'Barak', 'Guy',
            'Ted', 'Joey'
        }
        data5 = [(DOGS, BROWN_ANIMALS), (SATELLITES, LOW_EARTH_ORBIT),
                 (BOYS, HAPPY)]  # ALL

        GROUP_A = {'hello'}
        GROUP_B = {'hello'}
        GROUP_C = {'0', '2', '6', '17'}
        GROUP_D = {'0', '2', '6', '17'}
        data_1 = [(GROUP_A, GROUP_B),
                  (GROUP_C, GROUP_D)]  # Minimal Quantifier: NONE

        CATS = {'Mitzi', 'Tuli', 'KitKat', 'Chat', 'Ears'}
        TWEET = {'Tweety', 'Zebra Finch', 'Cockatoo'}
        HAVE_ONE_SOUL = {'Rex', 'John'}
        data7 = [(CATS, TWEET), (CATS, HAVE_ONE_SOUL), (CATS, DOGS)]

    def simulate_data_3(self):
        def make_list_of_set_pairs_2(at_least_not, at_most_not, list_size):
            Q = frozenset(range(1, at_most_not * 2))
            return [(frozenset(self.randomizer.get_prng().sample(
                Q,
                len(Q) - self.randomizer.get_prng().randint(
                    at_least_not, at_most_not))), Q) for i in range(list_size)]

        data3 = make_list_of_set_pairs_2(at_least_not=3,
                                         at_most_not=7,
                                         list_size=50)
        assert all(len(Q) - 10 <= len(P) <= len(Q) - 0 for P, Q in data3)

    def create_output_directory(self, quantifier_type,
                                additional_parameters_to_persist,
                                positive_examples, initial_temperature,
                                threshold, alpha):
        output_directory = os.path.join(
            run_dir(quantifier_type, initial_temperature, alpha, threshold),
            ('runid[%s]' % uuid.uuid4().hex))
        os.makedirs(output_directory)
        with open(os.path.join(output_directory, 'parameters.csv'),
                  'w') as params_f:
            params_f.write('initial_temperature,%s\n' % initial_temperature)
            params_f.write('threshold,%s\n' % threshold)
            params_f.write('alpha,%s\n' % alpha)
            for param_name, param_value in additional_parameters_to_persist.items(
            ):
                params_f.write('%s,%s\n' % (param_name, param_value))
        with open(os.path.join(output_directory, 'positive_examples.txt'),
                  'w') as pos_f:
            pos_f.write('\n'.join(positive_examples))
        return output_directory

    def __simulate_with_data(self, quantifier_type,
                             additional_parameters_to_persist, data,
                             initial_temperature, threshold, alpha):
        positive_examples = [
            get_binary_representation(Randomizer(self.randomizer.seed), set_a,
                                      set_b) for set_a, set_b in data
        ]
        output_directory = self.create_output_directory(
            quantifier_type, additional_parameters_to_persist,
            positive_examples, initial_temperature, threshold, alpha)
        annealer = DFA_Annealer(self.randomizer.seed)
        learner = Simulated_annealing_learner(self.randomizer.seed,
                                              initial_temperature, data,
                                              annealer)
        final_hyp = learner.logger(self.create_plots, positive_examples,
                                   output_directory, threshold, alpha)[0]
        return output_directory, final_hyp, positive_examples

    def simulate_BETWEEN_with_dynamic_universe_size(
            self, initial_temperature, threshold, alpha,
            add_examples_which_are_all_ones_of_these_lengths, at_least_ones,
            at_most_ones, min_size_of_universe, max_size_of_universe,
            number_of_positive_examples):
        data = self.make_list_of_set_pairs_for_quantifier_between(
            at_least_ones, at_most_ones, min_size_of_universe,
            max_size_of_universe, number_of_positive_examples,
            add_examples_which_are_all_ones_of_these_lengths)
        return self.__simulate_with_data(
            'BETWEEN_WITH_DYNAMIC_UNIVERSE_SIZE',
            dict(add_examples_which_are_all_ones_of_these_lengths=
                 add_examples_which_are_all_ones_of_these_lengths,
                 at_least_ones=at_least_ones,
                 at_most_ones=at_most_ones,
                 min_size_of_universe=min_size_of_universe,
                 max_size_of_universe=max_size_of_universe,
                 number_of_positive_examples=number_of_positive_examples),
            data, initial_temperature, threshold, alpha)

    def simulate_BETWEEN_with_fixed_universe_size(self, initial_temperature,
                                                  threshold, alpha, all_ones,
                                                  at_least_ones,
                                                  at_most_plus_1_ones,
                                                  fixed_universe_size,
                                                  number_of_positive_examples):
        data = self.make_list_of_set_pairs_for_quantifier_between(
            at_least_ones,
            at_most_plus_1_ones,
            min_size_of_universe=fixed_universe_size,
            max_size_of_universe=fixed_universe_size + 1,
            number_of_positive_examples=number_of_positive_examples,
            add_examples_which_are_all_ones_of_these_lengths=all_ones)
        return self.__simulate_with_data(
            'BETWEEN_WITH_FIXED_UNIVERSE_SIZE',
            dict(all_ones=all_ones,
                 at_least_ones=at_least_ones,
                 at_most_plus_1_ones=at_most_plus_1_ones,
                 fixed_universe_size=fixed_universe_size,
                 number_of_positive_examples=number_of_positive_examples),
            data, initial_temperature, threshold, alpha)

    def simulate_ALL(self, initial_temperature, threshold, alpha, min_set_size,
                     max_set_size, number_of_pairs):
        data = self.make_list_of_set_pairs_for_quantifier_all(
            min_set_size, max_set_size, number_of_pairs)
        return self.__simulate_with_data(
            'ALL',
            dict(min_set_size=min_set_size,
                 max_set_size=max_set_size,
                 number_of_pairs=number_of_pairs), data, initial_temperature,
            threshold, alpha)

    def simulate_NONE(self, initial_temperature, threshold, alpha,
                      min_set_size, max_set_size, number_of_pairs):
        data = self.make_list_of_set_pairs_for_quantifier_none(
            min_set_size, max_set_size, number_of_pairs)
        return self.__simulate_with_data(
            'NONE',
            dict(min_set_size=min_set_size,
                 max_set_size=max_set_size,
                 number_of_pairs=number_of_pairs), data, initial_temperature,
            threshold, alpha)

    def run_single_simulation(self, quantifier_type, initial_temperature,
                              threshold, alpha, *args, **kwargs):
        info('############ Starting simulation for quantifier %s' %
             quantifier_type)
        quantifier_names_to_functions = {
            'BETWEEN_WITH_DYNAMIC_UNIVERSE_SIZE':
            self.simulate_BETWEEN_with_dynamic_universe_size,
            'NONE':
            self.simulate_NONE,
            'EXACTLY':
            self.simulate_EXACTLY,
            'ALL':
            self.simulate_ALL,
            'ALL_OF_THE_EXACTLY':
            self.simulate_ALL_OF_THE_EXACTLY,
            'BETWEEN_WITH_FIXED_UNIVERSE_SIZE':
            self.simulate_BETWEEN_with_fixed_universe_size
        }
        qunatifier_names_to_target_dfa = {
            'NONE':
            target_automaton.expected_final_hyp_none(),
            'ALL':
            target_automaton.expected_final_hyp_all(),
            'BETWEEN_WITH_FIXED_UNIVERSE_SIZE':
            target_automaton.expected_final_hyp_between_with_any_universe_size(
                lower=kwargs.get('at_least_ones'),
                upper=kwargs.get('at_most_plus_1_ones')),
            'BETWEEN_WITH_DYNAMIC_UNIVERSE_SIZE':
            target_automaton.expected_final_hyp_between_with_any_universe_size(
                lower=kwargs.get('at_least_ones'),
                upper=kwargs.get('at_most_ones')),
            'EXACTLY':
            target_automaton.expected_final_hyp_exactly(kwargs.get('ns')),
            'ALL_OF_THE_EXACTLY':
            target_automaton.expected_final_hyp_all_of_the_exactly(
                kwargs.get('ns'))
        }
        if quantifier_type in quantifier_names_to_functions:
            output_directory, final_hyp, positive_examples = quantifier_names_to_functions[quantifier_type] \
                (initial_temperature, threshold, alpha, *args, **kwargs)
            final_hyp.plot_transitions('final_hyp', output_directory)
            is_success = (
                final_hyp == qunatifier_names_to_target_dfa[quantifier_type])
            with open(os.path.join(output_directory, 'is_success.txt'),
                      'w') as f_success:
                f_success.write(str(is_success))
            # with open(os.path.join(output_directory, 'energy_final_hyp_minus_target.csv'), 'w') as final_diff_f:
            #     final_diff_f.write(str(DFA_Annealer.energy_difference_a_minus_b(
            #             final_hyp,
            #             qunatifier_names_to_target_dfa[quantifier_type],
            #             positive_examples)) if quantifier_type in qunatifier_names_to_target_dfa \
            #                            else 'No target automaton defined')
            info(
                '############ Finished simulation for quantifier %s, output in %s'
                % (quantifier_type, output_directory))
            return is_success
        else:
            raise ValueError('Unknown quantifier type %s' % quantifier_type)