445 lines
14 KiB
Java
445 lines
14 KiB
Java
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<EResultElements, Object> result;
|
|
protected List<Map<ERoundResult, Object>> 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
|
|
* <p>
|
|
* 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<ERoundResult, Object> 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<ERoundResult, Object> 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<ERoundResult, Object> 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<ERoundResult, Object> 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<ERoundResult, Object> 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<EResultElements, Object> 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<EResultElements, Object> getResult() {
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Return n changes
|
|
*
|
|
* @param n
|
|
* Number of changes
|
|
* @return n changes
|
|
*/
|
|
protected double[] getNChanges(int n) {
|
|
return behaviorService.getNChanges(n);
|
|
}
|
|
}
|