structuredoutputcbr.adaptation.Adaptation.java Source code

Java tutorial

Introduction

Here is the source code for structuredoutputcbr.adaptation.Adaptation.java

Source

package structuredoutputcbr.adaptation;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

import structuredoutputcbr.StructuredOutputCBR;
import structuredoutputcbr.ontology.*;
import structuredoutputcbr.casebase.*;
import structuredoutputcbr.utils.*;
import java.util.*;
import org.apache.commons.collections4.CollectionUtils;

/**
 * CLASS THAT IMPLEMENTS THE ADAPTATION PHASE OF THE CBR
 * @author Joan T. Matamalas <jtmatamalas@gmail.com>
 */
public class Adaptation {
    private Case new_case; // The new case tried to be solved
    private Case retrieved; // The most similar case in the case base to the one tried to be solved

    /*-------------------------------------------
    ONTOLOGY ELEMENT SHORTCUTS
    -------------------------------------------*/

    private final OntologyElement planning_key = StructuredOutputCBR.ontology.getElement("planning");
    private final OntologyElement sessions_key = StructuredOutputCBR.ontology.getElement("sessions");
    private final OntologyElement program_key = StructuredOutputCBR.ontology.getElement("program");
    private final OntologyElement number_key = StructuredOutputCBR.ontology.getElement("number");
    private final OntologyElement type_key = StructuredOutputCBR.ontology.getElement("type");
    private final OntologyElement muscular_group_key = StructuredOutputCBR.ontology.getElement("muscular group");
    private final OntologyElement muscle_key = StructuredOutputCBR.ontology.getElement("muscle");
    private final OntologyElement handicaps_key = StructuredOutputCBR.ontology.getElement("handicaps");
    private final OntologyElement expertise_key = StructuredOutputCBR.ontology.getElement("expertise");
    private final OntologyElement relaxations_key = StructuredOutputCBR.ontology.getElement("relaxations");
    private final OntologyElement region_key = StructuredOutputCBR.ontology.getElement("region");
    private final OntologyElement exercise_key = StructuredOutputCBR.ontology.getElement("exercise");
    private final OntologyElement shedule_key = StructuredOutputCBR.ontology.getElement("schedule");

    /**
     * Principal Funcion. If a new_case description and its must similar case in the case base system it will performs an adaptation over the similar solution in order to adjust to the new construction.
     * @param new_case The new case description
     * @param retrieved The most similar case
     * @return The adapted solution to the new description
     */
    public Case adapt(Case new_case, Case retrieved) {

        this.new_case = new_case;//The new case

        this.retrieved = retrieved;//The retrieved case

        this.new_case.setSolution(new CaseBlock(this.retrieved.getSolution()));//Set the solution of the retrieved case as solution to the new case TO BE ADAPTEd

        //Get the number sessions of the recieved and new cases
        int number_of_sessions_retrieved = retrieved.getDescription().getAttributeInteger(this.sessions_key, 0);
        int number_of_sessions_new = new_case.getDescription().getAttributeInteger(this.sessions_key, 0);

        //Expertise level of the new case
        OntologyElement new_level = this.new_case.getDescription().getAttributeOntology(this.expertise_key, 0);

        //PERFORMS THE ADAPTATION OF THE NUMBER OF SESSIONS ATTIBUTE IF IS IT NECESSARY
        if (number_of_sessions_new < number_of_sessions_retrieved) {
            this.adaptHigherNumberOfSessions(number_of_sessions_new, number_of_sessions_retrieved);
        } else if (number_of_sessions_new > number_of_sessions_retrieved) {
            this.adaptLowerNumberOfSessions(number_of_sessions_new, number_of_sessions_retrieved);
        }

        //PERFORMS THE ADAPTATION OF THE EXPERTISE LEVEL, IF THE ADAPTATION IS REQUIRED IS CONTROLED INSIDE THE FUNCTION
        this.adaptExpertiseLevel(new_level);

        //IF THERE ARE RELAXATION, CALLS THE METHOD THAT APPLY THEM.
        if (!this.new_case.getDescription().getAttributeOntologies(this.relaxations_key).isEmpty()) {
            this.applyRelaxations();
        }

        //IF THERE ARE HANDICAPS, CALLS THE METHOD THAT APPLY THEM.
        if (!this.new_case.getDescription().getAttributeOntologies(this.handicaps_key).isEmpty()) {
            this.applyHandicapConstrains();
        }

        //CHECK THE ORDER OF THE EXERCISES IN THE PLANNING FOLLOWING THE PREFERENCE MATRIX
        for (int i = 0; i < this.new_case.getSolution().getAttributeComponents(this.planning_key).size(); i++) {
            Collections.sort((ArrayList<CaseBlock>) this.new_case.getSolution()
                    .getAttributeComponents(this.planning_key).get(i).getAttributeComponents(this.program_key),
                    StructuredOutputCBR.preferences);
        }

        //return the new case with the solution adapted
        return this.new_case;
    }

    /**
     * Adapt the solution if the case retrieved and the case tried to be solved differ in the number of sessions, x_new.sessions is less than x_retrieved.sessions
     * @param sessions_new Number of sessions in the description of the new case
     * @param sessions_retrieved Number of sessions in the description of the retrieved case.
     */
    private void adaptHigherNumberOfSessions(Integer sessions_new, Integer sessions_retrieved) {
        //Get a second similar case with number of sessions as discriminant value
        OntologyElement k = StructuredOutputCBR.ontology.getElement("sessions");
        KeyValuePair<OntologyElement, Integer> pair = new KeyValuePair<>(k, sessions_new);

        String type = (String) this.retrieved.getDescription().getAttributeOntology(this.type_key, 0).getName();

        ArrayList<CaseBlock> new_planning = new ArrayList();

        for (int day : this.new_case.getDescription().getAttributeIntegers(this.shedule_key)) {
            CaseBlock plan = new CaseBlock();
            plan.setAttributeContent(this.number_key, day);
            new_planning.add(plan);
        }

        ArrayList<Case> cases_r = StructuredOutputCBR.base.retrieveCasesByDescription(new_case, 1, pair);

        Case retrieved_2 = cases_r.get(0);

        this.new_case.setSolution(new CaseBlock(retrieved_2.getSolution()));

        //Array with all the muscular groups
        ArrayList<OntologyElement> muscular_groups = this.muscular_group_key.getRelationValues("items");

        // Get case exercises
        ArrayList<CaseBlock> planning_retrieved_1 = this.retrieved.getSolution()
                .getAttributeComponents(this.planning_key);
        ArrayList<CaseBlock> planning_retrieved_2 = retrieved_2.getSolution()
                .getAttributeComponents(this.planning_key);

        ArrayList<CaseBlock> exercicies_from_retrieved_1 = this.getAllExercisesFromAPlanning(planning_retrieved_1);
        ArrayList<CaseBlock> exercicies_from_retrieved_2 = this.getAllExercisesFromAPlanning(planning_retrieved_2);

        ArrayList<CaseBlock> new_exercise_set = new ArrayList();

        //Shuffle the muscular groups in order to get random day assignation. DELETE THE COMMMENT!!!!!
        Collections.shuffle(muscular_groups, new Random(1));

        //Iterate over all muscular groups
        for (OntologyElement group : muscular_groups) {
            //Get all the exercises for specific muscular group from the retrieved case
            ArrayList<CaseBlock> muscular_group_exercises_retrieved_1 = this
                    .getAllExercisesFromMuscularGroup(exercicies_from_retrieved_1, group);
            //Get all the exercises for specific muscular group from the second retrieved case
            ArrayList<CaseBlock> muscular_group_exercises_retrieved_2 = this
                    .getAllExercisesFromMuscularGroup(exercicies_from_retrieved_2, group);

            if ((muscular_group_exercises_retrieved_1.size() == muscular_group_exercises_retrieved_2.size())
                    || muscular_group_exercises_retrieved_2.isEmpty())
                continue;

            //Get the number of exercicies of both sets.
            int number_of_exercises_retrieved_2 = muscular_group_exercises_retrieved_2.size();

            ArrayList<ArrayList<CaseBlock>> combinations = nCr(muscular_group_exercises_retrieved_1,
                    number_of_exercises_retrieved_2);

            //Index of the best combination
            int best_combination_size = 0;
            ArrayList<CaseBlock> best_combination = new ArrayList();

            //Get the best combination
            for (ArrayList<CaseBlock> combination : combinations) {
                //The muscles for each intervening exercise
                ArrayList<ArrayList<OntologyElement>> muscles_for_exercises = new ArrayList();

                //Get all the muscles of the exercises
                for (CaseBlock exercise : combination) {
                    OntologyElement ex = exercise.getAttributeOntology(this.exercise_key, 0);
                    muscles_for_exercises.add(ex.getRelationValues("muscles"));
                }

                //Start the union of Muscles
                ArrayList<OntologyElement> unionMuscles = (ArrayList<OntologyElement>) muscles_for_exercises.get(0);

                //Make the union of all the muscular sets
                for (int i = 1; i < muscles_for_exercises.size(); i++) {
                    unionMuscles = (ArrayList<OntologyElement>) CollectionUtils.union(unionMuscles,
                            muscles_for_exercises.get(i));
                }

                Collections.sort(unionMuscles, new ComparatorMuscles());

                //Update the best
                if (unionMuscles.size() > best_combination_size) {
                    best_combination_size = unionMuscles.size();
                    best_combination = combination;
                }
            }
            new_exercise_set = (ArrayList<CaseBlock>) CollectionUtils.union(new_exercise_set, best_combination);
        }

        //Fill the planning
        this.fillPlanning(type, new_exercise_set, new_planning);

        //Set the new planning as a solution of the new case
        this.new_case.getSolution().setAttributeContent(this.planning_key, new_planning);
    }

    /**
     * Adapt the solution if the case retrieved and the case tried to be solved differ in the number of sessions, x_new.sessions is more than x_retrieved.sessions
     * @param sessions_new Number of sessions in the description of the new case
     * @param sessions_retrieved Number of sessions in the description of the retrieved case.
     */
    private void adaptLowerNumberOfSessions(Integer sessions_new, Integer sessions_retrieved) {
        //Get a second similar case with number of sessions as discriminant value
        OntologyElement k = StructuredOutputCBR.ontology.getElement("sessions");
        KeyValuePair<OntologyElement, Integer> pair = new KeyValuePair<>(k, sessions_new);

        String type = (String) this.retrieved.getDescription().getAttributeOntology(this.type_key, 0).getName();

        ArrayList<CaseBlock> new_planning = new ArrayList();

        for (int day : this.new_case.getDescription().getAttributeIntegers(this.shedule_key)) {
            CaseBlock plan = new CaseBlock();
            plan.setAttributeContent(this.number_key, day);
            new_planning.add(plan);
        }

        ArrayList<Case> cases_r = StructuredOutputCBR.base.retrieveCasesByDescription(new_case, 1, pair);

        Case retrieved_2 = cases_r.get(0);

        this.new_case.setSolution(new CaseBlock(retrieved_2.getSolution()));

    }

    /**
     * Adapt the solution if the case retrieved and the case tried to be solved differ the expertise level
     * @param new_level the level of the new case
     */
    private void adaptExpertiseLevel(OntologyElement new_level) {
        //The actual planning
        ArrayList<CaseBlock> planning = this.new_case.getSolution().getAttributeComponents(this.planning_key);

        //Get the exercises for a given dificulty value
        ArrayList<OntologyElement> begginerExercises = StructuredOutputCBR.ontology.getElement("beginner")
                .getRelationValues("exercises");
        ArrayList<OntologyElement> intermediateExercises = StructuredOutputCBR.ontology.getElement("intermediate")
                .getRelationValues("exercises");

        //All the used exercises
        ArrayList<OntologyElement> existingExercises = this.getAllExercisesFromAPlanning_OE(planning);

        //Adapt the plan
        for (CaseBlock session : planning) {
            ArrayList<CaseBlock> program = session.getAttributeComponents(this.program_key);

            for (CaseBlock ex : program) {
                //Actual exercise
                OntologyElement exercise = ex.getAttributeOntology(this.exercise_key, 0);
                //Level of the exercise
                OntologyElement exercise_level = exercise.getRelationValue("expertise");

                //If the level of the exercise if greater than the desired
                if ((new_level.getName().equalsIgnoreCase("beginner")
                        && (exercise_level.getName().equalsIgnoreCase("intermediate")
                                || exercise_level.getName().equalsIgnoreCase("advanced")))
                        || (new_level.getName().equalsIgnoreCase("intermediate")
                                && exercise_level.getName().equalsIgnoreCase("advanced"))) {
                    //Start the comprarator with the actual exercise
                    ExerciseComparatorDisjunction comparatorEx = new ExerciseComparatorDisjunction(exercise);
                    //If the level desired is beginner
                    if (new_level.getName().equalsIgnoreCase("beginner")) {
                        //Sort begginer exercises by the ones that has minimum disjunction
                        Collections.sort(begginerExercises, comparatorEx);
                        boolean substitution_found = false;

                        //Browse all the sorted begginer exercises
                        for (OntologyElement beg_exercise : begginerExercises) {
                            //compute the size of the intersection
                            int size_intersection = CollectionUtils
                                    .intersection(exercise.getRelationValues("muscles"),
                                            beg_exercise.getRelationValues("muscles"))
                                    .size();

                            //If this exercise exist in the current planning get the next exercise
                            if (existingExercises.contains(beg_exercise)) {
                                continue;
                            }

                            //If the size_intersection consider the intermediate exercises
                            if (size_intersection == 0) {
                                break;
                            } else {
                                //Else substitut the exercise
                                substitution_found = true;
                                ex.setAttributeContent(this.exercise_key, beg_exercise);
                                existingExercises.add(beg_exercise);
                                break;
                            }
                        }
                        if (substitution_found) {
                            continue;
                        }

                        //If(the actual level is advance conside the intermediate exercises
                        if (exercise_level.getName().contains("advanced")) {

                            //Sort the intermediate exercises by disjuntion
                            Collections.sort(intermediateExercises, comparatorEx);

                            //The same than before but with interemediate exercises
                            for (OntologyElement int_exercise : intermediateExercises) {
                                int size_intersection = CollectionUtils
                                        .intersection(exercise.getRelationValues("muscles"),
                                                int_exercise.getRelationValues("muscles"))
                                        .size();
                                if (existingExercises.contains(int_exercise)) {
                                    continue;
                                }
                                if (size_intersection == 0) {
                                    break;
                                } else {
                                    ex.setAttributeContent(this.exercise_key, int_exercise);
                                    existingExercises.add(int_exercise);
                                    break;
                                }
                            }
                        }

                        //If the dessired exercise is intermediate start with considering all the interemedite exercises
                    } else if (new_level.getName().equalsIgnoreCase("intermediate")) {
                        Collections.sort(intermediateExercises, comparatorEx);
                        boolean substitution_found = false;
                        for (OntologyElement int_exercise : intermediateExercises) {
                            int size_intersection = CollectionUtils
                                    .intersection(exercise.getRelationValues("muscles"),
                                            int_exercise.getRelationValues("muscles"))
                                    .size();
                            if (existingExercises.contains(int_exercise)) {
                                continue;
                            }
                            if (size_intersection == 0) {
                                break;
                            } else {
                                substitution_found = true;
                                ex.setAttributeContent(this.exercise_key, int_exercise);
                                existingExercises.add(int_exercise);
                                break;
                            }
                        }
                        if (substitution_found) {
                            continue;
                        }

                        //Then consider the begginer exercises
                        Collections.sort(begginerExercises, comparatorEx);

                        //Browse all the sorted begginer exercises
                        for (OntologyElement beg_exercise : begginerExercises) {
                            //compute the size of the intersection
                            int size_intersection = CollectionUtils
                                    .intersection(exercise.getRelationValues("muscles"),
                                            beg_exercise.getRelationValues("muscles"))
                                    .size();

                            //If this exercise exist in the current planning get the next exercise
                            if (existingExercises.contains(beg_exercise)) {
                                continue;
                            }

                            //If the size_intersection consider the intermediate exercises
                            if (size_intersection == 0) {
                                break;
                            } else {
                                //Else substitut the exercise
                                ex.setAttributeContent(this.exercise_key, beg_exercise);
                                existingExercises.add(beg_exercise);
                                break;
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Apply the relaxation constrains specified in the description of the new problem
     */
    private void applyRelaxations() {
        //List of all muscular relaxations
        ArrayList<OntologyElement> muscular_groups_handicaps = this.new_case.getDescription()
                .getAttributeOntologies(this.relaxations_key);

        //Iterate over all the relaxations
        for (OntologyElement group : muscular_groups_handicaps) {
            //The planning of the actual new case
            ArrayList<CaseBlock> planning = this.new_case.getSolution().getAttributeComponents(this.planning_key);

            //All the exercises of specific muscular group
            ArrayList<OntologyElement> exercises_mg = StructuredOutputCBR.ontology.getElement(group.getName())
                    .getRelationValues("exercises");

            //All the exercises of specific muscular group in the actual planning
            ArrayList<CaseBlock> exercises_mg_planing = this
                    .getAllExercisesFromMuscularGroup(this.getAllExercisesFromAPlanning(planning), group);

            //All the combinations of exercises in muscular grups whit size exercises_mg_planing
            ArrayList<ArrayList<OntologyElement>> combinations = this.nCr(exercises_mg,
                    exercises_mg_planing.size());

            //Sort element with the sepecific criterium detailed in the documentation union - intersection <TIME CONSUMING!!!!!!!!!!!!!>
            Collections.sort(combinations, Collections.reverseOrder(new ComparatorBetweenCombinations(group)));

            int used_exercises = 0;

            //Iterate over all the exercises of a planning and substitute the ones from specifc muscular group
            for (int day = 0; day < this.new_case.getDescription().getAttributeInteger(this.sessions_key,
                    0); day++) {
                for (int ex = 0; ex < this.new_case.getSolution().getAttributeComponents(this.planning_key).get(day)
                        .getAttributeComponents(this.program_key).size(); ex++) {
                    if (this.new_case.getSolution().getAttributeComponents(this.planning_key).get(day)
                            .getAttributeComponents(this.program_key).get(ex)
                            .getAttributeOntology(this.exercise_key, 0).getRelationValues("muscular groups")
                            .contains(group)) {
                        this.new_case.getSolution().getAttributeComponents(this.planning_key).get(day)
                                .getAttributeComponents(this.program_key).get(ex)
                                .setAttributeContent(this.exercise_key, combinations.get(0).get(used_exercises));
                        used_exercises++;
                    }
                }
            }

        }

    }

    /**
     * Apply the handicaps constrains specified in the description of the new problem
     */
    private void applyHandicapConstrains() {
        //Muscular groups handicaps constrains
        ArrayList<OntologyElement> muscular_groups_handicaps = this.new_case.getDescription()
                .getAttributeOntologies(this.handicaps_key);

        //All the planning
        ArrayList<CaseBlock> planning = this.new_case.getSolution().getAttributeComponents(this.planning_key);

        //Iterate over all the planning and remove the exercises that use the specified muscle groups from the planning
        for (int day = 0; day < planning.size(); day++) {
            CaseBlock session = planning.get(day);
            ArrayList<CaseBlock> exercises = session.getAttributeComponents(this.program_key);
            ArrayList<Integer> to_be_removed = new ArrayList();
            for (int ex_num = 0; ex_num < exercises.size(); ex_num++) {
                CaseBlock exercise_cb = exercises.get(ex_num);
                OntologyElement exercise = exercise_cb.getAttributeOntology(this.exercise_key, 0);
                ArrayList<OntologyElement> muscular_groups_exercise = exercise.getRelationValues("muscular groups");
                for (OntologyElement ex_mg : muscular_groups_exercise) {
                    if (muscular_groups_handicaps.contains(ex_mg)) {
                        to_be_removed.add(ex_num);
                        break;
                    }
                }
            }
            this.new_case.getSolution().getAttributeComponents(this.planning_key).get(day)
                    .delAttributeContents(this.program_key, to_be_removed);
        }
    }

    /*---------------------------------------------------------------
    AUXILIAR FUNCTIONS
    ---------------------------------------------------------------*/
    /**
     * Return all the case block exercises from a giving planing
     * @param planning An array with all the programs of a planing
     * @return An array with all the case blocks that represents an exercise of a planning
     */
    private ArrayList<CaseBlock> getAllExercisesFromAPlanning(ArrayList<CaseBlock> planning) {
        ArrayList<CaseBlock> exercises = new ArrayList();

        for (CaseBlock session : planning) {
            ArrayList<CaseBlock> program = session.getAttributeComponents(this.program_key);
            for (CaseBlock specification_program : program) {
                exercises.add(specification_program);
            }
        }
        return exercises;
    }

    private ArrayList<OntologyElement> getAllExercisesFromAPlanning_OE(ArrayList<CaseBlock> planning) {
        ArrayList<CaseBlock> exercises = this.getAllExercisesFromAPlanning(planning);
        ArrayList<OntologyElement> exercises_OE = new ArrayList();

        for (CaseBlock ex : exercises) {
            exercises_OE.add(ex.getAttributeOntology(this.exercise_key, 0));
        }

        return exercises_OE;
    }

    /**
     * Get all the exercises from a list of CaseBlock exercises from a muscular_group
     * @param exercises An array list of case block exercises
     * @param muscular_group A specific muscular group
     * @return all exercises of a muscular group
     */
    private ArrayList<CaseBlock> getAllExercisesFromMuscularGroup(ArrayList<CaseBlock> exercises,
            OntologyElement muscular_group) {
        ArrayList<CaseBlock> exercises_mg = new ArrayList();

        for (CaseBlock exercise : exercises) {
            ArrayList<OntologyElement> exe_muscular_groups = exercise.getAttributeOntology(this.exercise_key, 0)
                    .getRelationValues("muscular groups");

            for (OntologyElement exe_muscular_grup : exe_muscular_groups)
                if (exe_muscular_grup == muscular_group) {
                    exercises_mg.add(exercise);
                }
        }

        return exercises_mg;
    }

    /**
     * Check if a given muscular_group is in one of the primary zones (pectorales, piernas, espalda)
     * @param muscular_group Muscular group to check
     * @return The primary zone if the muscular group is in one of them or the null if it is not
     */
    private OntologyElement isPrimary(OntologyElement muscular_group) {
        if (muscular_group.getParent() == null) {
            if (muscular_group.getName().equalsIgnoreCase("pectorales")) {
                return StructuredOutputCBR.ontology.getElement("pectorales");
            } else {
                return null;
            }
        } else {
            if (muscular_group.getParent().getName().equalsIgnoreCase("espalda")) {
                return StructuredOutputCBR.ontology.getElement("espalda");
            } else if (muscular_group.getParent().getName().equalsIgnoreCase("piernas")) {
                return StructuredOutputCBR.ontology.getElement("piernas");
            } else {
                return null;
            }
        }
    }

    /**
     * Get the session day with less exercises assigned
     * @param planning the current planning
     * @return The id of the day with less exercises assigned
     */
    private int getIndexDayWithLessExercises(ArrayList<CaseBlock> planning) {

        int min_day = 0;
        int min_size = 9999999;

        for (int i = 0; i < planning.size(); i++) {
            CaseBlock p = planning.get(i);
            ArrayList<CaseBlock> program = p.getAttributeComponents(this.program_key);
            if (program.size() < min_size) {
                min_day = i;
                min_size = program.size();
            }
        }

        return min_day;
    }

    /**
     * Find if a exercises implies the use of a primary zone.
     * @param plan The caseblock of the exercise.
     * @return True if implies the use of a primary zone, false otherwise
     */
    private boolean isAPrimaryGroupExercise(CaseBlock plan) {
        OntologyElement exercise = plan.getAttributeOntology(this.exercise_key, 0);
        ArrayList<OntologyElement> ex_muscle = exercise.getRelationValues("muscular groups");
        for (OntologyElement group : ex_muscle) {
            if (this.isPrimary(group) != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * Fill the planning with a given set of exercises
     * @param type The type of a planning split or full body
     * @param new_exercise_set the set of exercises to use
     * @param new_planning a reference to the planning
     */
    private void fillPlanning(String type, ArrayList<CaseBlock> new_exercise_set,
            ArrayList<CaseBlock> new_planning) {

        //Hash map that stores the days where are assigned the primary zone exercises in the case of full body
        HashMap<OntologyElement, Integer> primary_exercise_days = new HashMap();

        Collections.sort(new_exercise_set, new CompareCaseBlocks());

        ArrayList<OntologyElement> used_muscular_groups = new ArrayList();
        used_muscular_groups.add(StructuredOutputCBR.ontology.getElement("pectorales"));
        used_muscular_groups.addAll(StructuredOutputCBR.ontology.getElement("espalda").getDirectChildren());
        used_muscular_groups.addAll(StructuredOutputCBR.ontology.getElement("piernas").getDirectChildren());
        Collections.shuffle(used_muscular_groups, new Random(42));
        for (CaseBlock exercise_cb : new_exercise_set) {
            OntologyElement exercise = exercise_cb.getAttributeOntology(this.exercise_key, 0);
            used_muscular_groups = (ArrayList<OntologyElement>) CollectionUtils.union(used_muscular_groups,
                    exercise.getRelationValues("muscular groups"));
        }

        Collections.sort(used_muscular_groups, new ComparatorMuscles());
        Collections.sort(used_muscular_groups, new ComparePrimary());

        //Fill the planning if is type split
        if (type.equalsIgnoreCase("split")) {

            for (OntologyElement group : used_muscular_groups) {
                int prefered_day = this.getIndexDayWithLessExercises(new_planning);
                OntologyElement primary = this.isPrimary(group);

                if (primary == null) {
                    ArrayList<CaseBlock> specific_exercises = this
                            .getAllExercisesFromMuscularGroup(new_exercise_set, group);

                    for (CaseBlock specific_ex : specific_exercises) {
                        if (!this.isAPrimaryGroupExercise(specific_ex)) {
                            new_planning.get(prefered_day).addAttributeContent(this.program_key, specific_ex);
                            new_exercise_set.remove(specific_ex);
                        }
                    }

                } else {

                    if (primary_exercise_days.keySet().contains(primary)) {
                        prefered_day = primary_exercise_days.get(primary);

                    } else {
                        boolean otherPrimaryDay = true;

                        while (otherPrimaryDay) {
                            prefered_day = (prefered_day + 1) % new_planning.size();
                            otherPrimaryDay = false;

                            for (OntologyElement key : primary_exercise_days.keySet()) {
                                if (primary_exercise_days.get(key) == prefered_day) {
                                    otherPrimaryDay = true;
                                }
                            }

                        }
                    }

                    ArrayList<CaseBlock> exercises_primary = this.getAllExercisesFromMuscularGroup(new_exercise_set,
                            group);
                    new_planning.get(prefered_day).addAttributeContent(this.program_key, exercises_primary);
                    new_exercise_set.removeAll(this.getAllExercisesFromMuscularGroup(new_exercise_set, group));
                    primary_exercise_days.put(primary, prefered_day);
                }
            }

            //fill the planning if is type split
        } else {
            Random rnd = new Random(42);

            for (OntologyElement group : used_muscular_groups) {

                ArrayList<CaseBlock> specific_exercises = this.getAllExercisesFromMuscularGroup(new_exercise_set,
                        group);
                ArrayList<Integer> days = this.new_case.getDescription().getAttributeIntegers(this.shedule_key);

                Collections.shuffle(days, rnd);

                while (!specific_exercises.isEmpty()) {

                    for (Integer day : days) {

                        if (specific_exercises.isEmpty()) {
                            break;
                        }

                        CaseBlock exercise = specific_exercises.remove(0);
                        this.new_case.getSolution().getAttributeComponents(this.planning_key).get(day)
                                .addAttributeContent(this.program_key, exercise);
                        new_exercise_set.remove(exercise);
                    }
                }
            }
        }
    }

    /**
    * Return a nCk of the exercises <Gosper's Hack>
    * @param exercises The exercises of the retrieved case.
    * @param k Of combinations to be generated.
    * @return A list of list which all possible combinations.
    */
    private ArrayList nCr(ArrayList exercises, int k) {
        ArrayList result = new ArrayList();

        int x = (1 << k) - 1;
        int limit = (1 << exercises.size());

        while (x < limit) {
            long y = x;

            ArrayList combination = new ArrayList();

            for (int i = Long.numberOfTrailingZeros(y); y != 0; i = Long.numberOfTrailingZeros(y)) {
                combination.add(exercises.get(i));
                y &= ~(1 << i);
            }

            result.add(combination);

            int c = x & -x;
            int r = x + c;
            x = (((r ^ x) >>> 2) / c) | r;
        }

        return result;
    }
}