package afryca.consensusmodel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.services.nls.Translation; import afryca.behavior.service.IBehaviorService; import afryca.consensusmodel.definition.EResultElements; import afryca.consensusmodel.definition.ERoundResult; import afryca.consensusmodel.l10n.Messages; import afryca.consensusmodel.variable.Variable; import afryca.consensusmodel.variable.definition.EVariableElements; import afryca.consensusmodel.variable.definition.EVariableTypes; import afryca.consensusmodel.variable.definition.MockVariableConfigurationElement; import afryca.consensusmodel.variable.definition.VariableRegistry; import afryca.structure.Structure; import afryca.structure.ranking.AbstractDominanceRanking; import afryca.structure.ranking.AlternativeRanking; /** * Interface for consensus models * * @author Sinbad² * @version 3.0 */ public abstract class ConsensusModel { // Extension point id public static final String EXTENSION_POINT = "afryca.consensusmodel"; //$NON-NLS-1$ public static final String EXPERTS = "experts"; //$NON-NLS-1$ public static final String ALTERNATIVES = "alternatives"; //$NON-NLS-1$ public static final String CRITERIA = "criteria"; //$NON-NLS-1$ public static final String PREFERENCES = "preferences"; //$NON-NLS-1$ public static final String WITH_FEEDBACK = "WithFeedback"; //$NON-NLS-1$ public static final String UNDEFINED = "undefined"; //$NON-NLS-1$ protected String[] experts; protected String[] alternatives; protected String[] criteria; protected Integer numberOfExperts; protected Integer numberOfAlternatives; protected Integer numberOfCriteria; protected Structure[] preferences; protected Map result; protected List> roundsResults; protected boolean validConfiguration; protected Variables variables = null; protected Configuration configuration; @Inject protected IBehaviorService behaviorService; @Inject protected IEclipseContext context; @Inject @Translation private Messages messages; /** * Set the consensus model variables * * @param variables * Consensus model variables */ public void setVariables(Variables variables) { this.variables = variables; setDefaultVariables(); } private void setDefaultVariables() { addArrayVariable(variables, EXPERTS, messages.experts_description, EVariableTypes.String); addArrayVariable(variables, ALTERNATIVES, messages.alternatives_description, EVariableTypes.String); addArrayVariable(variables, CRITERIA, messages.criteria_description, EVariableTypes.String); addArrayVariable(variables, PREFERENCES, messages.preferences_description, EVariableTypes.FPR); } private void addArrayVariable(Variables variables, String id, String description, EVariableTypes type) { MockVariableConfigurationElement configurationElement = new MockVariableConfigurationElement(); configurationElement.addAttribute(EVariableElements.id.name(), id); configurationElement.addAttribute(EVariableElements.description.name(), description); configurationElement.addAttribute(EVariableElements.type.name(), type.name()); configurationElement.addAttribute(EVariableElements.default_value.name(), null); configurationElement.addAttribute(EVariableElements.array_default_element_value.name(), null); configurationElement.addAttribute(EVariableElements.is_array.name(), Boolean.toString(true)); configurationElement.addAttribute(EVariableElements.is_internal.name(), Boolean.toString(true)); addVariable(variables, new VariableRegistry(configurationElement)); } private void addVariable(Variables variables, VariableRegistry variableRegistry) { Variable variable = ContextInjectionFactory.make(Variable.class, injectInChildContext(variableRegistry)); variables.addVariable(variable); } private IEclipseContext injectInChildContext(Object element) { IEclipseContext childContext = context.createChild(); ContextInjectionFactory.inject(element, childContext); childContext.set(element.getClass().getName(), element); return childContext; } /** * Return consensus model variables * * @return Consensus model variables */ public Variables getVariables() { return variables; } /** * Configure model * * @param configuration * Model configuration * * @return True valid configuration *

* False invalid configuration */ public boolean setConfiguration(Configuration configuration) { this.configuration = configuration; validConfiguration = true; setElementsConfiguration(); if (validConfiguration) { setModelConfiguration(); } return validConfiguration; } private void setElementsConfiguration() { try { roundsResults = new ArrayList<>(); setExpertsConfiguration(); setAlternativesConfiguration(); setCriteriaConfiguration(); setPreferencesConfiguration(); setConsensusModelInformationConfiguration(); } catch (Exception e) { validConfiguration = false; } } private void setExpertsConfiguration() { experts = (String[]) configuration.getValue(EXPERTS); numberOfExperts = experts.length; } private void setAlternativesConfiguration() { alternatives = (String[]) configuration.getValue(ALTERNATIVES); numberOfAlternatives = alternatives.length; } private void setCriteriaConfiguration() { criteria = (String[]) configuration.getValue(CRITERIA); numberOfCriteria = criteria.length; } private void setPreferencesConfiguration() throws CloneNotSupportedException { Structure[] configurationPreferences = (Structure[]) configuration.getValue(PREFERENCES); preferences = new Structure[numberOfExperts * numberOfCriteria + 1]; for (int i = 0; i < numberOfExperts * numberOfCriteria; i++) { preferences[i] = (Structure) configurationPreferences[i].clone(); } preferences[numberOfExperts * numberOfCriteria] = (Structure) configurationPreferences[0].clone(); preferences[numberOfExperts * numberOfCriteria].initialize(); configuration.setValue(PREFERENCES, preferences); } private void setConsensusModelInformationConfiguration() { result = new HashMap<>(); for (EResultElements element : EResultElements.values()) { result.put(element, UNDEFINED); } result.put(EResultElements.experts, experts); result.put(EResultElements.number_of_experts, numberOfExperts); result.put(EResultElements.alternatives, alternatives); result.put(EResultElements.number_of_alternatives, numberOfAlternatives); result.put(EResultElements.criteria, criteria); result.put(EResultElements.number_of_criteria, numberOfCriteria); } /** * Set model specific configuration */ protected abstract void setModelConfiguration(); /** * Pre save round result * * @param round * Current round * @param preferences2 * Current preferences * @param consensusDegreeAchieved * Consensus degree achieved */ public void preSaveRoundResult(int round, Structure[] preferences2,Float[][][] preferencesGroupVisualization, Float consensusDegreeAchieved) { Map r = new HashMap<>(); roundsResults.add(r); r.put(ERoundResult.round, round); r.put(ERoundResult.pre_preferences, clonePreferences(preferences2)); r.put(ERoundResult.pre_preferencesGroupVisualization, preferencesGroupVisualization.clone()); r.put(ERoundResult.pre_consensus_degree_achieved, consensusDegreeAchieved); computePreRoundResults(r); } protected Structure[] clonePreferences(Structure[] preferences2) { Structure[] result = new Structure[preferences2.length]; for (int pos = 0; pos < preferences2.length; pos++) { try { result[pos] = (Structure) ((Structure) preferences2[pos]).clone(); } catch (CloneNotSupportedException e) { // Nothing to do } } return result; } private void computePreRoundResults(Map roundResults) { Structure[] preferences = (Structure[]) roundResults.get(ERoundResult.pre_preferences); int[][] order = new int[numberOfExperts + 1][numberOfAlternatives]; AlternativeRanking[] ranking; AlternativeRanking[] orderedRanking = null; for (int i = 0; i <= numberOfExperts; i++) { ranking = selection(preferences[i]); orderedRanking = AlternativeRanking.orderRanking(ranking); for (int j = 0; j < numberOfAlternatives; j++) { order[i][j] = orderedRanking[j].getPosition() + 1; } } roundResults.put(ERoundResult.pre_ranking_of_alternatives, order); } private static AlternativeRanking[] selection(Structure preference) { AbstractDominanceRanking ranking = preference.createRanking(); return ranking.getAlternativesRanking(); } /** * Pos save round result * * @param currentPreferences * Current preferences * @param consensusDegreeAchieved * Consensus degree achieved * @param advises * Number of advises * @param preferences2 */ public void posSaveRoundResult(Structure[] currentPreferences,Float[][][] preferencesGroupVisualization, Float consensusDegreeAchieved, int[] advises) { Map r = roundsResults.get(roundsResults.size() - 1); r.put(ERoundResult.pos_preferences, clonePreferences(currentPreferences)); r.put(ERoundResult.pos_preferencesGroupVisualization,preferencesGroupVisualization.clone()); r.put(ERoundResult.pos_consensus_degree_achieved, consensusDegreeAchieved); r.put(ERoundResult.advices, advises); computePosRoundResults(r); } private void computePosRoundResults(Map roundResults) { Structure[] preferences = (Structure[]) roundResults.get(ERoundResult.pos_preferences); int[][] order = new int[numberOfExperts + 1][numberOfAlternatives]; AlternativeRanking[] ranking; AlternativeRanking[] orderedRanking = null; for (int i = 0; i <= numberOfExperts; i++) { ranking = selection(preferences[i]); orderedRanking = AlternativeRanking.orderRanking(ranking); for (int j = 0; j < numberOfAlternatives; j++) { order[i][j] = orderedRanking[j].getPosition() + 1; } } roundResults.put(ERoundResult.pos_ranking_of_alternatives, order); } /** * Pos save round result * * @param preferences2 * Current preferences * @param consensusDegreeAchieved * Consensus degree achieved * @param advises * Number of advises * @param preferences3 * Group's preferences */ public void posSaveRoundResult(Structure[] preferences2, Float[][][] preferencesGroupVisualization, Float consensusDegreeAchieved, int[] advises, Structure preferences3) { Map r = roundsResults.get(roundsResults.size() - 1); r.put(ERoundResult.pos_preferences, clonePreferencesUnion(preferences2, preferences3)); r.put(ERoundResult.pos_preferencesGroupVisualization,preferencesGroupVisualization ); r.put(ERoundResult.pos_consensus_degree_achieved, consensusDegreeAchieved); r.put(ERoundResult.advices, advises); computePosRoundResults(r); } protected Structure[] clonePreferencesUnion(Structure[] preferences2, Structure collective) { Structure[] result = new Structure[preferences2.length]; for (int pos = 0; pos < preferences2.length; pos++) { try { result[pos] = (pos < (preferences2.length - 1)) ? (Structure) ((Structure) preferences2[pos]).clone() : (Structure) ((Structure) collective).clone(); } catch (CloneNotSupportedException e) { // Nothing to do } } return result; } /** * Execute model * * @return Execution result */ public Map execute() { if (validConfiguration) { obtainConfigurationValues(); boolean firstRound = true; do { if (firstRound) { preFirstSaveRoundResults(); firstRound = false; } else { preSaveRoundResults(); } consensusRound(); posSaveRoundResults(); } while (mustBeCarriedOutAnotherRound()); computeExecutionResults(); } else { return null; } return getResult(); } /** * Obtain configuration values */ protected abstract void obtainConfigurationValues(); /** * Save in 'preferencesGroupVisualization' only one preference by expert and the collective of this preferences */ protected abstract Float[][][] obtainVisualizeValues(); /** * Save pre first round results */ protected abstract void preFirstSaveRoundResults(); /** * Save pre round results */ protected abstract void preSaveRoundResults(); /** * Carried out consensus round */ protected abstract void consensusRound(); /** * Save pos round results */ protected abstract void posSaveRoundResults(); /** * Must be carried out another round * * @return True if another round should take place, False in other case */ protected abstract boolean mustBeCarriedOutAnotherRound(); /** * Save execution results */ protected abstract void saveExecutionResults(); protected void computeExecutionResults() { saveExecutionResults(); Structure[] preferences = (Structure[]) configuration.getValue(PREFERENCES); if(result.get(EResultElements.classification_of_alternatives) == "undefined") { AlternativeRanking[] ranking = selection(preferences); AlternativeRanking[] orderedRanking = AlternativeRanking.orderRanking(ranking); String orderedRankingInStringFormat = AlternativeRanking.orderedAlternativesRankingToString(orderedRanking); this.result.put(EResultElements.ranking_of_alternatives, orderedRankingInStringFormat); this.result.put(EResultElements.solution_set_of_alternatives, AlternativeRanking.getAlternativesWithRankingPos(ranking, 1)); } this.result.put(EResultElements.preferences, preferences); this.result.put(EResultElements.rounds_results, roundsResults); } private static AlternativeRanking[] selection(Structure[] preferences) { return selection(preferences[preferences.length - 1]); } /** * Return execution result * * @return Execution result */ public Map getResult() { return result; } /** * Return n changes * * @param n * Number of changes * @return n changes */ protected double[] getNChanges(int n) { return behaviorService.getNChanges(n); } }