/**
* Name: Multicriteria
* Author: Patrick Taillandier
* Description: This model shows how to use different methods of multicriteria analysis to look for the best house. Five methods are used : 
* the Weighted_Means method , the Electre method , the Promethee method, the Fuzzy Choquet Integral  anc the Evidence Theory method. Each method uses 
* different criteria with different weights according to the methods used. 
* Tags: multi_criteria
*/

model multicriteria

global {
	float weight_standing <- 1.0;
	float weight_price <- 1.0;
	float weight_distance <- 1.0;
	float weight_area <- 1.0;
	float p_standing <- 0.5;
	float p_price <- 0.5;
	float p_distance <- 0.5;
	float p_area <- 0.5;
	float q_standing <- 0.0;
	float q_price <- 0.0;
	float q_distance <- 0.0;
	float q_area <- 0.0;
	float v_standing <- 1.0;
	float v_price <- 1.0;
	float v_distance <- 1.0;
	float v_area <- 1.0;
	float s_standing <- 1.0;
	float s_price <- 1.0;
	float s_distance <- 1.0;
	float s_area <- 1.0;
	float s1_standing <- 0.0;
	float s1_price <- 0.0;
	float s1_distance <- 0.0;
	float s1_area <- 0.0;
	float s2_standing <- 1.0;
	float s2_price <- 1.0;
	float s2_distance <- 1.0;
	float s2_area <- 1.0;
	float v1p_standing <- 0.0;
	float v1p_price <- 0.0;
	float v1p_distance <- 0.0;
	float v1p_area <- 0.0;
	float v2p_standing <- 1.0;
	float v2p_price <- 1.0;
	float v2p_distance <- 1.0;
	float v2p_area <- 1.0;
	float v1c_standing <- 0.0;
	float v1c_price <- 0.0;
	float v1c_distance <- 0.0;
	float v1c_area <- 0.0;
	float v2c_standing <- 0.0;
	float v2c_price <- 0.0;
	float v2c_distance <- 0.0;
	float v2c_area <- 0.0;
	
	//Lists that will store the different criteria to use for each method linked with their weights
	list criteria <- ["standing", "price", "distance", "area"];
	list criteria_WM <- [["name"::"standing", "weight" :: weight_standing],["name"::"price", "weight" :: weight_price],["name"::"distance", "weight" ::weight_distance],["name"::"area", "weight" :: weight_area]]; 
	list criteria_Electre <- [["name"::"standing", "weight" :: weight_standing, "p"::p_standing, "q"::q_standing, "v"::v_standing, "maximize" :: true],["name"::"price", "weight" :: weight_price, "p"::p_price, "q"::q_price, "v"::v_price,  "maximize" :: true],["name"::"distance", "weight" ::weight_distance, "p"::p_distance, "q"::q_distance, "v"::v_distance,  "maximize" :: true],["name"::"area", "weight" :: weight_area,  "p"::p_area, "q"::q_area, "v"::v_area,  "maximize" :: true]]; 
	list criteria_Promethee <- [["name"::"standing", "weight" :: weight_standing, "p"::p_standing, "q"::q_standing, "s"::s_standing, "maximize" :: true],["name"::"price", "weight" :: weight_price, "p"::p_price, "q"::q_price, "s"::s_price,  "maximize" :: true],["name"::"distance", "weight" ::weight_distance, "p"::p_distance, "q"::q_distance, "s"::s_distance,  "maximize" :: true],["name"::"area", "weight" :: weight_area,  "p"::p_area, "q"::q_area, "s"::s_area,  "maximize" :: true]];  
	list criteria_ET <- [["name"::"standing", "s1"::s1_standing, "s2"::s2_standing, "v1p"::v1p_standing, "v2p"::v2p_standing, "v1c"::v1c_standing, "v2c"::v2c_standing,"maximize" :: true],["name"::"price", "s1"::s1_price, "s2"::s2_price, "v1p"::v1p_price, "v2p"::v2p_price, "v1c"::v1c_price, "v2c"::v2c_price,  "maximize" :: true],["name"::"distance", "s1"::s1_distance, "s2"::s2_distance, "v1p"::v1p_distance, "v2p"::v2p_distance, "v1c"::v1c_distance, "v2c"::v2c_distance,  "maximize" :: true],["name"::"area", "s1"::s1_area, "s2"::s2_area, "v1p"::v1p_area, "v2p"::v2p_area, "v1c"::v1c_area, "v2c"::v2c_area, "maximize" :: true]];
	map,float> criteria_FC <- map, float>([ 
		[["standing"]::weight_standing, ["price"]::weight_price, ["distance"]:: weight_distance, ["area"]::weight_area,
		["standing","price"]::(weight_standing+weight_price) * 2/3,["area","price"]::(weight_standing+weight_price) * 2/3 , 
		["standing","price","area"]::(weight_standing+weight_price + weight_area) * 2/3]
	]); 
	
	init {
		create people;
		geometry free_space <- copy(shape);
		free_space <- free_space - 10;
		create house number: 15 {
			location <- any_location_in (free_space);
			free_space <- free_space - (shape + 10);
		}
	}
	
	reflex reset_selected {
		ask house {
			is_selected_WM <- false;
			is_selected_electre <- false;
			is_selected_promethee <- false;
			is_selected_ET <- false;
			is_selected_choquet <- false;
		}
		criteria_WM <- [["name"::"standing", "weight" :: weight_standing],["name"::"price", "weight" :: weight_price],["name"::"distance", "weight" ::weight_distance],["name"::"area", "weight" :: weight_area]]; 
		criteria_Electre <- [["name"::"standing", "weight" :: weight_standing, "p"::p_standing, "q"::q_standing, "v"::v_standing, "maximize" :: true],["name"::"price", "weight" :: weight_price, "p"::p_price, "q"::q_price, "v"::v_price,  "maximize" :: true],["name"::"distance", "weight" ::weight_distance, "p"::p_distance, "q"::q_distance, "v"::v_distance,  "maximize" :: true],["name"::"area", "weight" :: weight_area,  "p"::p_area, "q"::q_area, "v"::v_area,  "maximize" :: true]]; 
		criteria_Promethee <- [["name"::"standing", "weight" :: weight_standing, "p"::p_standing, "q"::q_standing, "s"::s_standing, "maximize" :: true],["name"::"price", "weight" :: weight_price, "p"::p_price, "q"::q_price, "s"::s_price,  "maximize" :: true],["name"::"distance", "weight" ::weight_distance, "p"::p_distance, "q"::q_distance, "s"::s_distance,  "maximize" :: true],["name"::"area", "weight" :: weight_area,  "p"::p_area, "q"::q_area, "s"::s_area,  "maximize" :: true]]; 
		criteria_ET <- [["name"::"standing", "s1"::s1_standing, "s2"::s2_standing, "v1p"::v1p_standing, "v2p"::v2p_standing, "v1c"::v1c_standing, "v2c"::v2c_standing,"maximize" :: true],["name"::"price", "s1"::s1_price, "s2"::s2_price, "v1p"::v1p_price, "v2p"::v2p_price, "v1c"::v1c_price, "v2c"::v2c_price,  "maximize" :: true],["name"::"distance", "s1"::s1_distance, "s2"::s2_distance, "v1p"::v1p_distance, "v2p"::v2p_distance, "v1c"::v1c_distance, "v2c"::v2c_distance,  "maximize" :: true],["name"::"area", "s1"::s1_area, "s2"::s2_area, "v1p"::v1p_area, "v2p"::v2p_area, "v1c"::v1c_area, "v2c"::v2c_area, "maximize" :: true]];
		criteria_FC <- map, float>([ 
		[["standing"]::weight_standing, ["price"]::weight_price, ["distance"]:: weight_distance, ["area"]::weight_area,
		["standing","price"]::(weight_standing+weight_price) * 2/3,["area","price"]::(weight_standing+weight_price) * 2/3 , 
		["standing","price","area"]::(weight_standing+weight_price + weight_area) * 2/3]]);
	}
	
}
	

species people  {
	aspect default {
		draw sphere(2) color: #red;
	}
	
	reflex choose_house_weighted_means {
		list cands <- houses_eval();
		int choice <- weighted_means_DM(cands, criteria_WM);
		if (choice >= 0) {
			ask (house at choice) {is_selected_WM <- true;}
		}
	}
	
	reflex choose_house_fuzzy_choquet {
		list cands <- houses_eval();
		int choice <- fuzzy_choquet_DM(cands, criteria, criteria_FC);
		if (choice >= 0) {
			ask (house at choice) {is_selected_choquet <- true;}
		}
	}
	
	reflex choose_house_promethee {
		list cands <- houses_eval();
		int choice <- promethee_DM(cands, criteria_Promethee);
		if (choice >= 0) {
			ask (house at choice) {is_selected_promethee <- true;}
		}
	}
	reflex choose_house_electre {
		list cands <- houses_eval();
		int choice <- electre_DM(cands, criteria_Electre, 0.7);
		if (choice >= 0) {
			ask (house at choice) {is_selected_electre <- true;}
		}
	}
	reflex choose_house_evidence_theory {
		list cands <- houses_eval();
		int choice <- evidence_theory_DM(cands, criteria_ET, true);
		if (choice >= 0) {
			ask (house at choice) {is_selected_ET <- true;}
		}
	}
	
	list houses_eval {
		list candidates;
		loop bat over: house {
			list cand;
			add bat.standing / 5 to: cand;
			add ((500000 - bat.price) / 500000) to: cand;
			add ((100 - (self distance_to bat)) / 100) to: cand;
			add (bat.shape.area / 15^2) to: cand;
			add cand to: candidates;
		}
		return candidates;
	}
	
}

species house {
	bool is_selected_WM <- false;
	bool is_selected_electre <- false;
	bool is_selected_promethee <- false;
	bool is_selected_ET <- false;
	bool is_selected_choquet <- false;
	geometry shape <- square(5 + rnd(10));
	float price <- 100000.0 + rnd (400000);
	int standing <- rnd(5);
	rgb color <- rgb(255 * (1 - standing/5.0),255 * (1 - standing/5.0),255);
	float height <- price / 50000;
	aspect weighted_means_aspect {
		if (is_selected_WM) {
			draw shape + 2.0 color: #red;
		}
		draw shape color: color depth: height;
	}
	aspect electre_aspect {
		if (is_selected_electre) {
			draw shape + 2.0 color: #red;
		}
		draw shape color: color depth: height;
	}
	aspect promethee_aspect {
		if (is_selected_promethee) {
			draw shape + 2.0 color: #red;
		}
		draw shape color: color depth: height;
	}
	aspect evidence_theory_aspect {
		if (is_selected_ET) {
			draw shape + 2.0 color: #red;
		}
		draw shape color: color depth: height;
	}
	aspect choquet_aspect {
		if (is_selected_choquet) {
			draw shape + 2.0 color: #red;
		}
		draw shape color: color depth: height;
	}
}


experiment multicriteria type: gui {
	parameter "weight of the standing criterion" var:weight_standing category: "Weight";
	parameter "weight of the price criterion" var:weight_price category: "Weight";
	parameter "weight of the distance criterion" var:weight_distance category: "Weight";
	parameter "weight of the area criterion" var:weight_area category: "Weight";
	parameter "preference threshold of the standing criterion" var:p_standing category: "Preference";
	parameter "preference threshold of the price criterion" var:p_price category: "Preference";
	parameter "preference threshold of the distance criterion" var:p_distance category: "Preference";
	parameter "preference threshold of the area criterion" var:p_area category: "Preference";
	parameter "indifference threshold of the standing criterion" var:q_standing category: "Indifference";
	parameter "indifference threshold of the price criterion" var:q_price category: "Indifference";
	parameter "indifference threshold of the distance criterion" var:q_distance category: "Indifference";
	parameter "indifference threshold of the area criterion" var:q_area category: "Indifference";
	parameter "veto threshold of the standing criterion" var:v_standing category: "Veto";
	parameter "veto threshold of the price criterion" var:v_price category: "Veto";
	parameter "veto threshold of the distance criterion" var:v_distance category: "Veto";
	parameter "veto threshold of the area criterion" var:v_area category: "Veto";
	parameter "max preference value of the standing criterion" var:v_standing category: "Max preference value";
	parameter "max preference value of the price criterion" var:v_price category: "Max preference value";
	parameter "max preference value of the distance criterion" var:v_distance category: "Max preference value";
	parameter "max preference value of the area criterion" var:v_area category: "Max preference value";
	parameter "min criterion threshold of the standing criterion" var:s1_standing category: "Evidence Theory";
	parameter "min criterion threshold of the price criterion" var:s1_price category: "Evidence Theory";
	parameter "min criterion threshold of the distance criterion" var:s1_distance category: "Evidence Theory";
	parameter "min criterion threshold of the area criterion" var:s1_area category: "Evidence Theory";
	parameter "max criterion threshold of the standing criterion" var:s2_standing category: "Evidence Theory";
	parameter "max criterion threshold of the price criterion" var:s2_price category: "Evidence Theory";
	parameter "max criterion threshold of the distance criterion" var:s2_distance category: "Evidence Theory";
	parameter "max criterion threshold of the area criterion" var:s2_area category:"Evidence Theory";
	parameter "min preference of the standing criterion" var:v1p_standing category: "Evidence Theory";
	parameter "min preference of the price criterion" var:v1p_price category: "Evidence Theory";
	parameter "min preference of the distance criterion" var:v1p_distance category: "Evidence Theory";
	parameter "min preference of the area criterion" var:v1p_area category: "Evidence Theory";
	parameter "max preference of the standing criterion" var:v2p_standing category: "Evidence Theory";
	parameter "max preference of the price criterion" var:v2p_price category: "Evidence Theory";
	parameter "max preference of the distance criterion" var:v2p_distance category: "Evidence Theory";
	parameter "max preference of the area criterion" var:v2p_area category: "Evidence Theory";
	parameter "min rejection of the standing criterion" var:v1c_standing category: "Evidence Theory";
	parameter "min rejection of the price criterion" var:v1c_price category: "Evidence Theory";
	parameter "min rejection of the distance criterion" var:v1c_distance category: "Evidence Theory";
	parameter "min rejection of the area criterion" var:v1c_area category: "Evidence Theory";
	parameter "max rejection of the standing criterion" var:v2c_standing category: "Evidence Theory";
	parameter "max rejection of the price criterion" var:v2c_price category: "Evidence Theory";
	parameter "max rejection of the distance criterion" var:v2c_distance category: "Evidence Theory";
	parameter "max rejection of the area criterion" var:v2c_area category: "Evidence Theory";
	output {
		layout #split;
		display Map_Weighted_Means type: opengl{
			species house aspect: weighted_means_aspect;
			species people;
		}
		display Map_Electre type: opengl{
			species house aspect: electre_aspect;
			species people;
		}
		display Map_Promethee type: opengl{
			species house aspect: promethee_aspect;
			species people;
		}
		display Map_Evidence_theory type: opengl{
			species house aspect: evidence_theory_aspect;
			species people;
		}
		display Map_Choquet type: opengl{
			species house aspect: choquet_aspect;
			species people;
		}
	}
}