예제 #1
0
def test_make_decision():
    dec = Decisions()
    decision, decision_point, sims = dec.make_decision(
        'E',
        set(['S13', 'S14', 'H11']), [('W', 'S12'), ('N', 'H12')], [],
        random=True)
    # This will only work for naive decision maker of picking first valid card
    assert (decision in ['S13', 'S14'])
    assert_equal(decision_point, True)

    decision, decision_point, sims = dec.make_decision(
        'E',
        set(['H13', 'H14', 'H11']), [('W', 'S12'), ('N', 'H12')], ['H13'],
        random=True)
    # This will only work for naive decision maker of picking first valid card
    assert (decision in ['H14', 'H13', 'H11'])
    assert_equal(decision_point, True)

    decision, decision_point, sims = dec.make_decision(
        'E',
        set(['S13', 'S14', 'H11']), [('W', 'S12'), ('N', 'H12')], ['S13'],
        random=True)
    # This will only work for naive decision maker of picking first valid card
    assert_equal(decision, 'S14')
    assert_equal(decision_point, False)
예제 #2
0
def test_play_to_leaf_with_sims():
    d = Deal(seed=0)
    disp = Displayer()
    dec = Decisions()
    sim = Simulator()
    e = GameEngine(disp, dec, sim)

    sims = sim.load_sims(0)
    d = e.play_to_leaf(d, sims, random=False)
    assert_equal(d.full_history[0][1], d.trick_tally)
예제 #3
0
    def __init__(self, experiment, agent_kwargs):
        """ Load params
        """
        # dump kwarg dictionary into the agent object
        for key, value in agent_kwargs.iteritems():
            setattr(self, key, value)

        self.decisions = Decisions(self.decision_policy, self.stimulus_memory_n_timesteps)

        if experiment.is_simulation:
            self._simulated_agent_init(experiment)
예제 #4
0
def test_play_to_all_leaves():
    d = Deal(seed=0)
    d.make_lead()
    # print(d.original_hands)
    disp = Displayer()
    dec = Decisions()
    sim = Simulator()
    e = GameEngine(disp, dec, sim)
    e.play_to_all_leaves(d)
    assert_equal(d.trick_no, 5)
    assert_equal(d.card_no, 17)
    assert_equal(d.current_trick, [])
    # we save this number from a previous run. Good to check we always traverse the whole tree
    assert_equal(d.leaf_nodes, 832)
예제 #5
0
def test_find_all_layouts_and_run_sims():
    deal = {
        'N': set(['C14', 'C13', 'C12', 'C11']),
        'E': set(['S14', 'S13', 'H12', 'H11']),
        'S': set(['D14', 'D13', 'H14', 'H13']),
        'W': set(['D12', 'D11', 'S12', 'S11'])
    }
    d = Deal(deal=deal)
    sim = Simulator()
    dec = Decisions()
    disp = Displayer()

    e = GameEngine(disp, dec, sim)
    d.make_lead('D12')
    layouts = sim.find_layouts(d)
    # This should be the case because west has played a card already and north/south haven't
    assert (len(layouts[2]) > len(layouts[0]))
예제 #6
0
def test_play_to_leaf():
    deal = {
        'N': set(['C14', 'C13', 'C12', 'C11']),
        'E': set(['S14', 'S13', 'H12', 'H11']),
        'S': set(['D14', 'D13', 'H14', 'H13']),
        'W': set(['D12', 'D11', 'S12', 'S11'])
    }
    d = Deal(deal=deal)
    disp = Displayer()
    dec = Decisions()
    sim = Simulator()
    e = GameEngine(disp, dec, sim)
    e.play_to_leaf(d)
    assert_equal(d.trick_no, 5)
    assert_equal(d.card_no, 17)
    assert_equal(d.current_trick, [])
    assert_equal(d.leaf_nodes, 1)
예제 #7
0
def test_generate_possible_layouts():
    d = Deal(seed=0)
    disp = Displayer()
    dec = Decisions()
    sim = Simulator()
    e = GameEngine(disp, dec, sim)

    layouts = sim.generate_layouts('NS',
                                   set(['D12', 'D11', 'S12', 'S11']),
                                   set(['C14', 'C13', 'C12', 'C11']),
                                   d.all_cards,
                                   lead=set([]))

    assert_equal(len(layouts), scipy.special.comb(8, 4))
    my_layout = {
        'N': set(['C14', 'C13', 'C12', 'C11']),
        'E': set(['S14', 'S13', 'H12', 'H11']),
        'S': set(['D12', 'D11', 'S12', 'S11']),
        'W': set(['D14', 'D13', 'H14', 'H13'])
    }
예제 #8
0
class Control:
    """
    Control class
    """
    def __init__(self):
        """
        Initialise
        """
        self.decisions = Decisions()
        self.action_rules = ()

    def read_csv(self, file: str, **kwargs):
        """
        Create data frame from csv
        """
        # Find all couples of classification rules and try to create action rules
        self.decisions.read_csv(file, **kwargs)

    def load_pandas(self, data_frame: pd.DataFrame):
        """
        Load data frame
        """
        self.decisions.load_pandas(data_frame)

    def fit(self,
            stable_antecedents: List[str],
            flexible_antecedents: List[str],
            consequent: str,
            conf: float,
            supp: float,
            desired_classes: List[str] = None,
            desired_changes: List[list] = None,
            is_nan: bool = False,
            is_reduction: bool = True,
            min_stable_antecedents: int = 1,
            min_flexible_antecedents: int = 1):
        """
        Get action rules.
        Define antecedent and consequent.
        - stable_antecedents - List of column names.
        - flexible_antecedents - List of column names.
        - consequent - Name of column.
        Confidence and support.
        - conf - value in % for confidence of classification rules.
        - supp - value in % for support of classification rules.
        Desired classes or desired changes must be entered.
        - desired_classes - List of decision states. For example ["1"]. DEFAULT: None
        - desired_changes - List of desired changes. For example [["0", "1"]]. DEFAULT: None
        Should nan values be used.
        - is_nan - True means nan values are used, False means nan values are not used. DEFAULT: FALSE
        Should the reduction table be used.
        - is_reduction - is reduction table used DEFAULT: TRUE
        Minimal number of stable and flexible couples
        - min_stable_antecedents - min. stable couples. DEFAULT: 1
        - min_flexible_antecedents - min. flexible couples. DEFAULT: 1
        """
        if bool(desired_classes) != bool(desired_changes):
            desired_state = DesiredState(desired_classes=desired_classes,
                                         desired_changes=desired_changes)
        else:
            raise Exception(
                "Desired classes or desired changes must be entered")
        antecedents = stable_antecedents + flexible_antecedents
        self.decisions.prepare_data_fim(antecedents, consequent)
        self.decisions.fit_fim_apriori(conf=conf, support=supp)
        self.decisions.generate_decision_table()
        stable = self.decisions.decision_table[stable_antecedents]
        flex = self.decisions.decision_table[flexible_antecedents]
        target = self.decisions.decision_table[[consequent]]
        supp = self.decisions.support
        conf = self.decisions.confidence
        reduced_tables = Reduction(stable, flex, target, desired_state, supp,
                                   conf, is_nan)
        if is_reduction:
            reduced_tables.reduce()
        action_rules = ActionRules(
            reduced_tables.stable_tables, reduced_tables.flexible_tables,
            reduced_tables.decision_tables, desired_state, reduced_tables.supp,
            reduced_tables.conf, is_nan, min_stable_antecedents,
            min_flexible_antecedents)
        action_rules.fit()
        self.action_rules = action_rules.action_rules

    def get_action_rules(self) -> Tuple:
        """
        Get action rules.
        """
        return self.action_rules
예제 #9
0
 def __init__(self):
     """
     Initialise
     """
     self.decisions = Decisions()
     self.action_rules = ()
예제 #10
0
파일: engine_dep.py 프로젝트: Brewing1/SDS
        deal.save_leaf_node()
        return deal

    def play_to_all_leaves(self, deal):
        # Play hand for the first time, reaching our first leaf node and noting down all other
        # decision nodes in self.decision_points 
        deal = self.play_to_leaf(deal, random=True)
        # While there are still unexplored areas of game tree, go back to most recent decision
        # and make another one

        while deal.decision_points:
            last_decision_position = deal.decision_points[-1]

            deal.restore_position(last_decision_position)

            # Play the hand again from a specific position, noting down the card number and card
            # of the last decision made
            deal = self.play_to_leaf(deal, random=True)

        return deal.full_history


if __name__ == '__main__':

    decisions = Decisions()
    simulator = Simulator()

    game = Engine(decisions, simulator)
    # game.play_to_leaf()
    # game.play_to_all_leaves()
예제 #11
0
class Simulator:
    """Our simulated mosquito.
    """

    def __init__(self, experiment, agent_kwargs):
        """ Load params
        """
        # dump kwarg dictionary into the agent object
        for key, value in agent_kwargs.iteritems():
            setattr(self, key, value)

        self.decisions = Decisions(self.decision_policy, self.stimulus_memory_n_timesteps)

        if experiment.is_simulation:
            self._simulated_agent_init(experiment)

    def _simulated_agent_init(self, experiment):
        # defaults
        self.mass = 2.88e-6  # avg. mass of our colony (kg) =2.88 mg,
        self.time_max = 15.
        self.dt = 0.01
        self.max_bins = int(np.ceil(self.time_max / self.dt))  # N bins

        # from gassian fit to experimental control data
        self.initial_velocity_mu = 0.18
        self.initial_velocity_stdev = 0.08

        # useful aliases
        self.experiment = experiment
        self.windtunnel = self.experiment.environment.windtunnel
        self.bounded = self.experiment.experiment_conditions['bounded']
        self.boundary = self.windtunnel.boundary
        self.heat = self.experiment.environment.heat

        # useful lists TODO: get rid of?
        self.kinematics_list = ['position', 'velocity', 'acceleration']  # curvature?
        self.forces_list = ['total_f', 'random_f', 'stim_f']
        self.other_list = ['tsi', 'times', 'decision', 'heat_signal', 'in_plume']

        # mk forces
        self.flight = Flight(self.random_f_strength,
                             self.stim_f_strength,
                             self.damping_coeff)

        # turn thresh, in units deg s-1.
        # From Sharri:
        # it is the stdev of the broader of two Gaussians that fit the distribution of angular velocity

        # # create repulsion landscape
        # self._repulsion_funcs = repulsion_landscape3D.landscape(boundary=self.boundary)

    def fly(self, n_trajectories=1):
        """ runs _generate_flight n_trajectories times
        """
        df_list = []
        traj_i = 0
        try:
            if self.verbose:
                print """Starting simulations with {} heat model and {} decision policy.
                If you run out of patience, press <CTL>-C to stop generating simulations and
                cut to the chase scene.""".format(
                self.heat.heat_model_name, self.decision_policy)

            while traj_i < n_trajectories:
                # print updates
                if self.verbose:
                    sys.stdout.write("\rTrajectory {}/{}".format(traj_i + 1, n_trajectories))
                    sys.stdout.flush()

                array_dict = self._generate_flight()

                # if len(array_dict['velocity_x']) < 5:  # hack to catch when optimizer makes trajectories explode
                #     print "catching explosion"
                #     break

                # add label column to enumerate the trajectories
                array_len = len(array_dict['tsi'])
                array_dict['trajectory_num'] = [traj_i] * array_len

                # mk df, add to list of dfs
                df = pd.DataFrame(array_dict)
                # df = df.set_index(['trajectory_num'])
                df_list.append(df)

                traj_i += 1

                if traj_i == n_trajectories:
                    if self.verbose:
                        sys.stdout.write("\rSimulations finished. Performing deep magic.")
                        sys.stdout.flush()

        except KeyboardInterrupt:
            print "\n Simulations interrupted at iteration {}. Moving along...".format(traj_i)
            pass

        observations = Observations()
        observations.kinematics = pd.concat(df_list)  # concatenate all the data frames at once for performance boost.

        return observations

    def _generate_flight(self):
        """Generate a single trajectory using our model.
    
        First put everything into np arrays stored inside of a dictionary
        """
        dt = self.dt
        m = self.mass
        vector_dict = self._initialize_vector_dict()

        # # dynamically create easy-to-read aliases for the contents of vector_dict
        # for key, value in vector_dict.iteritems():
        #     exec(key + " = vector_dict['" + key + "']")
        # unpack vector dict into nicer aliases
        in_plume = vector_dict['in_plume']
        heat_signal = vector_dict['heat_signal']
        position = vector_dict['position']
        velocity = vector_dict['velocity']
        acceleration = vector_dict['acceleration']
        random_f = vector_dict['random_f']
        stim_f = vector_dict['stim_f']
        total_f = vector_dict['total_f']
        decision = vector_dict['decision']

        position[0] = self._set_init_position()
        velocity[0] = self._set_init_velocity()

        for tsi in vector_dict['tsi']:
            in_plume[tsi] = self.heat.check_in_plume_bounds(position[tsi])  # returns False for non-Bool plume

            decision[tsi], heat_signal[tsi] = self.decisions.make_decision(in_plume[tsi], velocity[tsi][1])

            if heat_signal[tsi] == 'X':  # this is an awful hack telling us to look up the gradient
                heat_signal[tsi] = self.heat.get_nearest_gradient(position[tsi])

            stim_f[tsi], random_f[tsi], total_f[tsi] = self.flight.calc_forces(velocity[tsi], decision[tsi], heat_signal[tsi])

            # calculate current acceleration
            acceleration[tsi] = total_f[tsi] / m

            # check if time is out, end loop before we solve for future velo, position
            if tsi == self.max_bins-1: # -1 because of how range() works
                vector_dict = self._land(tsi, vector_dict)
                break

            ################################################
            # Calculate candidate velocity and positions
            ################################################
            candidate_velo = velocity[tsi] + acceleration[tsi] * dt

            # make sure velocity doesn't diverge to infinity if system is unstable
            # this stops the optimizer from crashing
            candidate_velo = self._velocity_ceiling(candidate_velo)

            candidate_pos = position[tsi] + candidate_velo * dt

            ################################################
            # test candidates
            ################################################
            if self.bounded:
                candidate_pos, candidate_velo = self._collide_with_wall(candidate_pos, candidate_velo)

            position[tsi + 1] = candidate_pos
            velocity[tsi + 1] = candidate_velo

        # once flight is finished, make dictionary ready to be loaded into DF
        vector_dict = self._fix_vector_dict(vector_dict)

        return vector_dict

    def _land(self, tsi, V):
        ''' trim excess timebins in arrays
        '''
        if tsi == 0:  # hack for if we need to chop a trajectory at the very start
            for k, array in V.iteritems():
                V[k] = array[:1]
        else:
            for k, array in V.iteritems():
                V[k] = array[:tsi - 1]
                V[k] = array[:tsi - 1]
        
        return V

    def _collide_with_wall(self, candidate_pos, candidate_velo):
        walls = self.windtunnel.walls
        xpos, ypos, zpos = candidate_pos
        xvelo, yvelo, zvelo = candidate_velo
        teleport_distance = 0.005  # this is arbitrary
        crash = False

        # print "test", candidate_velo

        # x dim
        if xpos < walls.downwind:  # too far behind
            crash = True
            xpos = walls.downwind + teleport_distance  # teleport back inside
            if self.collision_type == 'elastic':
                xvelo *= -1.
            elif self.collision_type == 'part_elastic':
                xvelo *= -self.restitution_coeff
            elif self.collision_type == 'crash':
                xvelo = 0.
            else:
                raise ValueError("unknown collision type {}".format(self.collision_type))
        if xpos > walls.upwind:  # reached far (upwind) wall (end)
            crash = True
            xpos = walls.upwind - teleport_distance  # teleport back inside
            if self.collision_type == 'elastic':
                xvelo *= -1.
            elif self.collision_type == 'part_elastic':
                xvelo *= -self.restitution_coeff
            elif self.collision_type == 'crash':
                xvelo = 0.


        # y dim
        if ypos < walls.left:  # too left
            crash = True
            ypos = walls.left + teleport_distance
            if self.collision_type == 'elastic':
                yvelo *= -1.
            elif self.collision_type == 'part_elastic':
                yvelo *= -self.restitution_coeff
            elif self.collision_type == "crash":
                yvelo = 0.

        if ypos > walls.right:  # too far right
            crash = True
            ypos = walls.right - teleport_distance
            if self.collision_type == 'elastic':
                yvelo *= -1.
            elif self.collision_type == 'part_elastic':
                yvelo *= -self.restitution_coeff
            elif self.collision_type == 'crash':
                yvelo = 0.

        # z dim
        if zpos > walls.ceiling:  # too far above
            crash = True
            zpos = walls.ceiling - teleport_distance
            if self.collision_type == 'elastic':
                zvelo *= -1.
            elif self.collision_type == 'part_elastic':
                zvelo *= -self.restitution_coeff
            elif self.collision_type == "crash":
                zvelo = 0.
        if zpos < walls.floor:  # too far below
            crash = True
            zpos = walls.floor + teleport_distance
            if self.collision_type == 'elastic':
                zvelo *= -1.
            elif self.collision_type == 'part_elastic':
                zvelo *= -self.restitution_coeff
            elif self.collision_type == 'crash':
                zvelo = 0.

        try:
            candidate_pos, candidate_velo = np.array([xpos, ypos, zpos]), np.array([xvelo, yvelo, zvelo])
        except:
            print " cand velo", [xvelo, yvelo, zvelo], "before", candidate_velo


        return candidate_pos, candidate_velo

    def _initialize_vector_dict(self):
        """
        initialize np arrays, store in dictionary
        """
        V = {}

        for name in self.kinematics_list + self.forces_list:
            V[name] = np.full((self.max_bins, 3), np.nan)

        V['tsi'] = np.arange(self.max_bins)
        V['times'] = np.linspace(0, self.time_max, self.max_bins)
        V['in_plume'] = np.zeros(self.max_bins, dtype=bool)
        V['heat_signal'] = np.array([None] * self.max_bins)
        V['decision'] = np.array([None] * self.max_bins)

        return V

    def _set_init_velocity(self):
        initial_velocity_norm = np.random.normal(self.initial_velocity_mu, self.initial_velocity_stdev, 1)

        unit_vector = generate_random_unit_vector()
        velocity_vec = initial_velocity_norm * unit_vector

        return velocity_vec

    def _set_init_position(self):
        ''' puts the agent in an initial position, usually within the bounds of the
        cage

        Options: [the cage] door, or anywhere in the plane at x=.1 meters

        set initial velocity from fitted distribution
        '''

        # generate random intial velocity condition using normal distribution fitted to experimental data
        if self.initial_position_selection == 'realistic':
            """these were calculated by taking selecting the initial positions of all observed trajectories in all
            conditions. Then, for each dimension, I calculated the distance of each initial position to the nearest wall
            in that dimension (i.e. for each z I calculated the distance to the floor and ceiling and selected
            the smallest distance. Then, Decisions aand"""
            downwind, upwind, left, right, floor, ceiling = self.boundary
            x_avg_dist_to_wall = 0.268
            y_avg_dist_to_wall = 0.044
            z_avg_dist_to_wall = 0.049
            x = choose([(downwind + x_avg_dist_to_wall), (upwind - x_avg_dist_to_wall)])
            y = choose([left + y_avg_dist_to_wall, (right - y_avg_dist_to_wall)])
            z = ceiling - z_avg_dist_to_wall
            initial_position = np.array([x,y,z])
        elif self.initial_position_selection == 'downwind_high':
            initial_position = np.array(
                [0.05, np.random.uniform(-0.127, 0.127), 0.2373])  # 0.2373 is mode of z pos distribution
        elif type(self.initial_position_selection) is list:
            initial_position = np.array(self.initial_position_selection)
        elif self.initial_position_selection == "door":  # start trajectories as they exit the front door
            initial_position = np.array([0.1909, np.random.uniform(-0.0381, 0.0381), np.random.uniform(0., 0.1016)])
            # FIXME cage is actually suspending above floor
        elif self.initial_position_selection == 'downwind_plane':
            initial_position = np.array([0.1, np.random.uniform(-0.127, 0.127), np.random.uniform(0., 0.254)])
        else:
            raise Exception('invalid agent position specified: {}'.format(self.initial_position_selection))

        return initial_position

    def _velocity_ceiling(self, candidate_velo):
        """check if we're seeing enormous velocities, which sometimes happens when running the optimization
         algoirithm. if so, cap the velocity instead of landing. this allows the optimizer to keep running.
        """
        for i, velo in enumerate(candidate_velo):
            if velo > 20:
                candidate_velo[i] = 20.
            elif velo < -20:
                candidate_velo[i] = -20.

        return candidate_velo

    def _fix_vector_dict(self, dct):
        # prepare dict for loading into pandas (dataframe only accepts 1D vectors)
        # split xyz dicts into separate x, y, z vectors for dataframe

        fixed_dct = {}
        for kinematic in self.kinematics_list + self.forces_list:
            fixed_dct[kinematic + '_x'], fixed_dct[kinematic + '_y'], fixed_dct[kinematic + '_z'] = np.split(
                dct[kinematic], 3, axis=1)

        # migrate rest of dict
        for v in self.other_list:
            fixed_dct[v] = dct[v]

        # fix pandas bug when trying to load (R,1) arrays when it expects (R,) arrays
        for key, dct in fixed_dct.iteritems():
            fixed_dct[key] = fixed_dct[key].reshape(len(dct))
            if fixed_dct[key].size == 0:
                fixed_dct[key] = np.array([0.])  # hack so that kde calculation doesn't freeze on empty arrays

        return fixed_dct
    cols = ['my_score', 'max_score']
    df = pd.DataFrame(Y1, columns=cols)
    df['is_beast'] = df['my_score'] == df['max_score']
    vc = df['is_beast'].value_counts()
    true_percentage = vc[True] / (vc[True] + vc[False]) * 100
    return true_percentage


attempt_count = 10000
X = np.random.randint(1, 7, (attempt_count, 4))
strategies = np.array([[4, 3, 2], [4, 4, 3], [5, 4, 3], [5, 4, 4], [5, 5, 3],
                       [3, 3, 3], [4, 4, 4], [5, 5, 5], [6, 6, 6], [5, 5, 4]])

all_results = []
for str in strategies:
    Y = get_true_perc(dc.get_value(X, str))
    all_results.append(Y)
    print('True percentage {} : {}%'.format(str, Y))

print(max(all_results))
str_len = len(strategies)
plt.plot(range(str_len), all_results)
plt.plot(range(str_len), all_results, 'ro')

x_ticks = strategies
plt.xticks(range(str_len), x_ticks)
plt.title('Decision Efficiency with {} training set'.format(attempt_count))
plt.xlabel('Input data')
plt.ylabel('True Percentage %')
plt.show()
예제 #13
0
def autofis_onecv(file_zip, file_train, file_test, parameters):
    # General parameters
    t_norm = parameters[3]
    max_size_of_premise = parameters[5]
    association_method = parameters[11]
    aggregation_method = parameters[12]

    # Gathering parameters
    # Formulation parameters:
    par_area, par_over, par_pcd = toolfis.get_formulation_parameters(parameters)

    # 1. Lecture & Fuzzification
    out1 = toolfis.lecture_fuz_one_cv(file_zip, file_train, file_test, parameters)
    ux_train, cbin_train = out1[0]
    ux_test, cbin_test = out1[1]
    num_premises_by_attribute, premises_by_attribute, ref_attributes, premises_contain_negation = out1[2]
    freq_classes = out1[3]

    report = []  # To save our results

    try:
        # 3. Formulation
        f2 = Formulation(ux_train, cbin_train, ref_attributes, premises_by_attribute,
                         num_premises_by_attribute, premises_contain_negation)
        # Inputs given by user
        arbol = f2.gen_ARB(max_size_of_premise, t_norm, par_area, par_over, par_pcd)

        status = [0 if not i[0] else 1 for i in arbol]
        sum_status = sum(status)
        if sum_status != len(arbol):
            if sum_status == 0:
                raise ValueError("Error in Formulation Module. Any premise survived. "
                                 "Sorry, you can not continue in the next stage."
                                 "\nTry to change the configuration")
            else:
                arb = [i for i in arbol if i[0]]
                arbol, arb = arb, arbol

        number_classes = cbin_train.shape[1]

        report.append("\nFormulation:\n-----------------")
        report.append("Elementos acorde a la profundidad " + str(len(arbol)) + " del arbol")
        for i in range(len(arbol)):
            report.append('Profundidad ' + str(i + 1) + ': ' + str(arbol[i][1].shape))
            # print 'Profundidad ' + str(i + 1) + ': ' + str(arbol[i][1].shape)

        # 4. Association: ex-Division
        f3 = Association(arbol, cbin_train)
        premises_ux_by_class = f3.division(association_method)

        status = [0 if not i[0] else 1 for i in premises_ux_by_class]
        if sum(status) != number_classes:
            raise ValueError("Error in Division Module. Some classes did not get premises. "
                             "Sorry, you can not continue in the next stage."
                             "\nTry to change the configuration")

        # 5. Aggregation:
        f4 = Aggregation(premises_ux_by_class, cbin_train)
        output_aggregation = f4.aggregation(aggregation_method)

        premises_weights_names = output_aggregation[0]
        estimation_classes = output_aggregation[1]

        status = [0 if not i[0] else 1 for i in premises_weights_names]
        if sum(status) != number_classes:
            raise ValueError("Error in Aggregation Module. Some classes did not get premises. "
                             "Sorry, you can not continue in the next stage."
                             "\nTry to change the configuration")

        final_premises_classes = []
        report.append("\n\nPremises:\n=========")
        for i in range(len(premises_weights_names)):
            report.append("Premises of Class " + str(i) + ": " + str(premises_weights_names[i][0]))
            final_premises_classes.append(premises_weights_names[i][0])
            report.append("weights_" + str(i) + ": " + str(premises_weights_names[i][1].T))

        # 6. Decision:
        f5 = Decisions(estimation_classes, freq_classes)
        train_bin_prediction = f5.dec_max_pert()

        # 7. Evaluation
        f6 = Evaluation(premises_weights_names, final_premises_classes, freq_classes)
        metrics_train = f6.eval_train(cbin_train, train_bin_prediction)
        metrics_test = f6.eval_test(cbin_test, ux_test, t_norm)

        report.append("\nEvaluation Training:\n---------------------------")
        report.append("Accuracy on train dataset: " + str(metrics_train[0]))
        report.append("AUC in train dataset: " + str(metrics_train[1]))
        report.append("Recall: " + str(metrics_train[3]))
        report.append('Confusion matrix:\n' + str(metrics_train[2]))

        report.append("\nEvaluation Testing:\n---------------------------")
        report.append("Accuracy on test dataset: " + str(metrics_test[0]))
        report.append("AUC in test dataset: " + str(metrics_test[1]))
        report.append("Recall: " + str(metrics_test[3]))
        report.append("Confusion matrix:\n" + str(metrics_test[2]))

        # Metrics to eval: accuracy_test, auc_test,
        #                  [num_regras, total_rule_length, tamano_medio_das_regras]]
        metricas = [1, [metrics_train[0], metrics_test[0], metrics_train[1], metrics_test[1], metrics_test[4]]]

    except ValueError as e:
        print e
        report = e  # .append("\n" + str(e))
        metricas = [0, "No se termino el proceso, se detuvo en algun etapa"]

    return report, metricas