%************************************************************************************** % Appendix S6: source code %************************************************************************************** %Read me: %This text document presents the source code of the article %Rule-Based Modeling of Chronic Disease Epidemiology: %Elderly Depression as an Illustration %Jean-Christophe Chiêm, Jean Macq, Niko Speybroeck %published in Plos One %Installation and Instructions for users can be found in Appendix 6 %The .m files are presented here in a row: %Parameters.m %param_TypeAll.m %param_Type1.m %param_Type2.m %param_Type3.m %param_TypeA.m %param_TypeB.m %They can be downloaded via the following links: %https://sourceforge.net/projects/rbmelddep/. %************************************************************************************** %Parameters.m %************************************************************************************** %*************************************************** %Global Declaration %*************************************************** global num_eld global new_birth global num_it global max_age global min_age global min_age_male_wedding global max_age_male_wedding global age_path global rate_dep_f global rate_dep_m global treatment_rate global disadvantagedSES_rate global gender_rate global age_std global max_age global min_age global min_age_male_wedding global max_age_male_wedding global age_path global rate_dep_f global rate_dep_m global rate_married_women global treatment_rate global disadvantagedSES_rate global prop_dispatch_SES global gender_rate global age_std global year_widow_depression global check_treatment global check_SES % 0 no consideration of SES % 1consideration of SES global type %*************************************************** %Scenario % %*************************************************** % 0 no treatement % 1 apply treatement_rate check_treatment =0; % 0 no consideration of SES % 1 consideration of SES check_SES=0; %*************************************************** %Type %*************************************************** %must be one of the string: '1','2','3','A','B','All' type = 'All' %*************************************************** %Value of other parameters %*************************************************** num_eld=1000; % number of elderly new_birth=num_eld; % number of elderly to add each year num_it=35; % number of iterations for 1 simulation %age decay between women (younger) and men (older) % women with man between can get married between max_age=92; %(they die at max_age+1 ) min_age=61; %() min_age_male_wedding = 62; max_age_male_wedding = 63; %age path (between min age and max age, consecutives) age_path=[65 70 75 80 82]; %treatment rate (between 0,1) treatment_rate=0.169; %HIS % probability of being in a defavorized socio economic status (between 0,1) disadvantagedSES_rate =0.1153; %HIS %threshold at 65 there are 186 women for 147men(between 0,1) (HIS) gender_rate= 186/(186+147); % 55.8% %standard deviation for age_path (positive) age_std=2; %ratio of depressed men and women at 61.(between 0,1) rate_dep_f= 27/165; rate_dep_m= 16/164; %threshold at 65 there are in average (2001-2004-2008) %All9688+6877+4526=21091 (singles/widow/ divorced) %for 34769 marrie women(following eurostat) rate_married_women = 34769 / (16565+ 34769); %ratio of impact probabilities (+1,0) redistributed onto (-1) % ex: 4 means 1/4 of the probabilities of (+1,0) are allocated on (-1) % prop_dispatch_SES=4; %(positiveinteger>1) % force a year of depression 1 (disable 0) year_widow_depression =1; %************ %check %************ if age_path(1,1)< min_age disp('parameter error: age_path(1,1)< min_age') end %************************************************************************************** %param_TypeAll.m %************************************************************************************** function [prob_impact_unit prob_plan_non_dep prob_plan_dep] = param_typeAll disp('TypeAll') prob_impact_unit = [23.50,22.7857142857143,16.9285714285714,22.7857142857143,69.0357142857143;18.8571428571429,19.5714285714286,28.6785714285714,46.50,18.75;57.6428571428571,57.6428571428571,54.3928571428571,30.7142857142857,12.2142857142857;]; prob_plan_non_dep =[50.8571428571429,5,14.2857142857143,11.5714285714286,11.4642857142857;26.9642857142857,51.25,41.7857142857143,36.2142857142857,35.6071428571429;7.17857142857143,15.4285714285714,11.1785714285714,30.2142857142857,34.6785714285714;8.96428571428571,15.1428571428571,15.0714285714286,8.82142857142857,5.10714285714286;6.03571428571429,13.1785714285714,17.6785714285714,13.1785714285714,13.1428571428571;]; prob_plan_dep =[46.6071428571429,4.750,12.9285714285714,10.1428571428571,8.750;23.3928571428571,42.5714285714286,38.50,33.1071428571429,33.2142857142857;12.8928571428571,20.9642857142857,18.8571428571429,33.2142857142857,35.6071428571429;5.03571428571429,9.21428571428571,7.96428571428571,5.07142857142857,4.42857142857143;12.0714285714286,22.50,21.75,18.4642857142857,18;]; end %************************************************************************************** %param_Type1.m %************************************************************************************** function [prob_impact_unit prob_plan_non_dep prob_plan_dep] =param_type1 disp('Type1') prob_impact_unit = [17.50,22.50,10,25,71.25;35,43.75,41.25,53.75,26.25;47.50,33.75,48.75,21.25,2.500;]; prob_plan_non_dep = [47.50,15,30,20,22.50;25,37.50,17.50,17.50,20;9.500,30,16.25,38.75,40;15,13.75,16.25,7.500,2.500;3,3.750,20,16.25,15;]; prob_plan_dep = [38.75,15,30,15,18.75;27.50,27.50,25,22.50,18.75;20.75,32.50,22.50,46.25,48.75;3,7.500,6.250,2.500,1.250;10,17.50,16.25,13.75,12.50;]; end %************************************************************************************** %param_Type2.m %************************************************************************************** function [prob_impact_unit prob_plan_non_dep prob_plan_dep] =param_type2 disp('Type2') prob_impact_unit = [23.3076923076923,21.7692307692308,18.7692307692308,23.3076923076923,71.7692307692308;12.9230769230769,15.6153846153846,27.1538461538462,44.3846153846154,11.6153846153846;63.7692307692308,62.6153846153846,54.0769230769231,32.3076923076923,16.6153846153846;]; prob_plan_non_dep = [53.9230769230769,0,2.30769230769231,1.92307692307692,2.30769230769231;26.1538461538462,58.4615384615385,53.8461538461539,44.6153846153846,45;7.07692307692308,12.8461538461538,11.3076923076923,29.6153846153846,35.3846153846154;8.23076923076923,17.7692307692308,18.4615384615385,12.7692307692308,5.84615384615385;4.61538461538462,10.9230769230769,14.0769230769231,11.0769230769231,11.4615384615385;]; prob_plan_dep = [51.1538461538462,0,1.84615384615385,1.92307692307692,1.53846153846154;21.1538461538462,48.0769230769231,46.9230769230769,38.3076923076923,40;11,19,19.1538461538462,32.6923076923077,33.0769230769231;5.61538461538462,11.6153846153846,10.4615384615385,7.23076923076923,6;11.0769230769231,21.3076923076923,21.6153846153846,19.8461538461538,19.3846153846154;]; end %************************************************************************************** %param_Type3.m %************************************************************************************** function [prob_impact_unit prob_plan_non_dep prob_plan_dep] =param_type3 disp('Type3') prob_impact_unit = ... [25.9090909090909,24.0909090909091,17.2727272727273,21.3636363636364,65; 20,15.4545454545455,25.9090909090909,46.3636363636364,24.4545454545455; 54.0909090909091,60.4545454545455,56.8181818181818,32.2727272727273,10.5454545454545;]; prob_plan_non_dep =... [48.4545454545455,7.27272727272727,22.7272727272727,19.9090909090909,18.2727272727273;28.6363636363636,47.7272727272727,36.3636363636364,33.0909090909091,30.1818181818182;6.45454545454545,13.1818181818182,9.18181818181818,27.8181818181818,31.9090909090909;7.63636363636364,12.5454545454545,10.6363636363636,4.63636363636364,5.18181818181818;8.81818181818182,19.2727272727273,21.0909090909091,14.5454545454545,14.4545454545455;]; prob_plan_dep = [44.0909090909091,6.63636363636364,19.8181818181818,18.0909090909091,13.6363636363636;24.5454545454545,41.5454545454546,33.4545454545455,30.8181818181818,30.4545454545455;12.2727272727273,19.0909090909091,17.1818181818182,29.0909090909091,33.8181818181818;5.09090909090909,7,5.63636363636364,3.45454545454545,3.72727272727273;14,25.7272727272727,23.9090909090909,18.5454545454545,18.3636363636364;]; end %************************************************************************************** %param_TypeA.m %************************************************************************************** function [prob_impact_unit prob_plan_non_dep prob_plan_dep] = param_typeA disp('TypeA') prob_impact_unit = ... [23.7777777777778,22.9444444444444,14.9444444444444,22.3888888888889,70.4444444444444;19.8888888888889,17.9444444444444,32.9444444444444,47.6111111111111,14.7222222222222;56.3333333333333,59.1111111111111,52.1111111111111,30,14.8333333333333;]; prob_plan_non_dep =... [52.7777777777778,0,0,0,0;26.9444444444444,56.3888888888889,51.3888888888889,42.2222222222222,42;6.66666666666667,13.3333333333333,13.0555555555556,30.50,37.7222222222222;7.38888888888889,15.8333333333333,14,9.55555555555556,4.500;6.22222222222222,14.4444444444444,21.5555555555556,17.7222222222222,15.7777777777778;]; prob_plan_dep =.... [37,13.30,36.20,28.40,24.50;27,35.70,27,24.40,25;16.20,21.20,13,31.90,33.80;5.600,9.800,10.50,5,4.400;14.20,20,13.30,10.30,12.30;]; end %************************************************************************************** %param_TypeB.m %************************************************************************************** function [prob_impact_unit prob_plan_non_dep prob_plan_dep] = param_typeB disp('TypeB') prob_impact_unit =... [23,22.50,20.50,23.50,66.50; 17,22.50,21,44.50,26; 60,55,58.50,32,7.500;]; prob_plan_non_dep =... [47.40,14,40,32.40,32.10; 27,42,24.50,25.40,24.10; 8.100,19.20,7.800,29.70,29.20; 11.80,13.90,17,7.500,6.200; 5.700,10.90,10.70,5,8.400;]; prob_plan_dep = ... [37,13.30,36.20,28.40,24.50; 27,35.70,27,24.40,25; 16.20,21.20,13,31.90,33.80; 5.600,9.800,10.50,5,4.400; 14.20,20,13.30,10.30,12.30;]; end %************************************************************************************** %Simulation_RBM_eld_dep.m %************************************************************************************** %*********************************************************************** % Rule-based simulation of elderly depression % considering the gender distinction and a wedding procedure %*********************************************************************** %@author: Jean-Christophe %@date : 04/2012 % % @pre: %------ % % WS_list: this list of indices represents the number % of times the simulation should be run. % ex: to run the simulation 50 enter the list 1:50 % WS_dir: directory where to save the .mat files generated for each % simulations % Prefix: Prefix of the name of the .mat files generated for each % simulations % % nb: - the parameters of the simualtion are defined % in the parameters.m file (scenario parameters, % selection of a typology of experts, size of the population,...) % - the experts'answers of each typology are saved in specific .m files % ex: param_typeA.m (for expert of Type A) % % @post: %---------- % The parameters of parameters.m are loaded. % The parameters of the typology of experts requested % in parameters.m are loaded % % Multiple simulation are generated for one scenario and one type of % experts, considering the gender distinction and a wedding procedure % For each simulation a Workspace with all the relevant information is saved % in WSdir with name Prefix_typex_y.mat where x refers to the typology of % experts and y the number of iterations. THis workspace records: % - values of the parameters, Contact and Impact tables % - scenario info (check_treatment, check_SES) % - prevalences of the last iterations of the simulation (myprev_m1) % - indices of fit computes by functions compute_TS and % compute_Num_index(see their specifications). % - other variables are only technique variables % For each simulation the prevalences of the current simulation are saved % and accumulated in variable myprev_m1. % These saved prevalences are then averaged and the mean is % drawn together with the empirical prevalences retrieved %from The online Belgian Health Interview Survey (HIS) % and the associated regression line. % % @example: %---------- % To run 50 simulations and save your 50 workspaces % in the directory '/Users/Desktop/test' % with prefix of name 'My_simulation' % use the following command % % [myprev_m1]= ... % Simulation_RBM_eld_dep(1:50, '/Users/Desktop/test',... % 'My_simulation'); % % myprev_m1 holds the prevalences by age of the last iterations of % 50 simulations %*********************************************************** %Multiple Simulations %*********************************************************** function myprev_m1= Simulation_RBM_eld_dep(WS_list, WS_dir, prefix) global n_m1 global n_z0 global n_p1 global prob_impact_unit global prob_plan_non_dep global prob_plan_dep global type global check_treatment global check_SES % 0 no consideration of SES % 1consideration of SES %**************************** %parameters & expert answers %**************************** parameters myparam=strcat('param_type',type); [prob_impact_unit prob_plan_non_dep prob_plan_dep] =eval(myparam); %**************************** %simulations %**************************** [a,b]=size(WS_list); myprev_m1=[]; % prevalences of depression by age for my_it=1:b ext=num2str(WS_list(1,my_it)) %one simulation sim_process; %save the current prevalence n_tot=n_m1+n_p1+n_z0; prev_m1= (n_m1./n_tot)*100; myprev_m1=[myprev_m1; prev_m1]; %save WS in the right directory for analysis process_dir=pwd; cd(WS_dir); my_prefix= strcat(prefix,'_type',type,'_'); WS_file=strcat(my_prefix,ext); save (WS_file); cd(process_dir); end %**************************** %drawing %**************************** close all draw_empirical_filigrane; draw_one_plot(myprev_m1); draw_regression; %**************************** %stat %**************************** TS = compute_TS(myprev_m1); within_CI = compute_Num_index(myprev_m1); fit_index = [within_CI TS] end %*********************************************************** %One Simulation %*********************************************************** %% %****************************************************** %@pre: parameters have been loaded (parameters.m) %@post: one simulation (WITH wedding procedure) % - an initial population is created % - women are married to men % - each individuals goes through an individual process % - a treatment effect may be applied to the population % (check_treatment=1) % - new individuals are added to the population % - they die at the beginning of the next iteration %****************************************************** %*********************************************************** %Simulation %*********************************************************** %% function sim_process %*************************************************** %Data structure %*************************************************** global n_m1 % number of depressed DS global n_z0 % number of neutral DS global n_p1 % number of non-depressed DS global state % variable (columns) for each individual (row) global num_eld global new_birth global num_it global eld_var_num global prob_impact_unit global prob_impact_unit_dis %SES %*************************************************** global check_treatment global check_SES %*************************************************** global prob_plan_dep global prob_plan_non_dep global prob_plan_dep_single global prob_plan_non_dep_single %********************** %Initiatlization %********************** %[age,depression state; age_path; sex; marita_status; spouse_index; % widow_history; SES]; if check_SES==1 eld_var_num=12; else %[age,depression state; age_path; sex; marita_status; % spouse_index; widow_history]; eld_var_num=11; end %computed contact tables for singles prob_plan_dep_single = prob_plan_for_single (prob_plan_dep); prob_plan_non_dep_single = prob_plan_for_single (prob_plan_non_dep); %SES consideration generationt of a specific prob_impact if check_SES==1 prob_impact_unit_dis=generate_prob_impact_unit_SES(prob_impact_unit); end %data for dying process delta_dead = die_delta_dead (num_eld); %initial_population state = gen_birth(num_eld); %nb no wedding possible at this stage cause everybody's 55 %*************************************************** %Iterative process %*************************************************** for current_it =1:num_it %each year %display if mod(current_it,5)==0 current_it end %dying process (remove indiviudual subsequently to fit empirical mortality %rate between 65 and 92) %natural death is retrieved here state= die(state, delta_dead); %Individual process state = individual_process(state); %treatment if check_treatment==1 state=treatment(state); end %birth process birth = gen_birth(new_birth); state=[state;birth]; clear birth %wedding process state=wedding(state); % update age_path for singles after birth (after max_age_male_wedding) state = update_age_path(state); end %******************************** %prevalence and demographic stat %******************************** %demographic stat population=[current_it size(state,1) histc(state(:,8),0:1)' histc(state(:,9),0:2)']; %prevalence compuation [n_m1 n_z0 n_p1] = get_n(state); end %*************************************************** %Individual process %*************************************************** %% %****************************************************** %@pre: state is a matrix with the all population %@post: Widows for only one year stay depressed and only their age is % is incremented % Other individual are processed (for one year): % - a contact with a source of social support is selecte (evt_type) % - an impact is selected possibly integrating a SES distinction % (check_SES=1) % - the age incremented %****************************************************** function state = individual_process(state) global check_SES [a,b]=size(state); % a= number of elderly persons % b= num-of variables for j = 1: a % for each individu still alive if (state(j,11)==0)% for those who are not widow just since last year %select evt type evt_type = evt_selection(state(j,:)); %consider marital status %given evt type compute the impact for an individual if check_SES==1 new_state = evt_impact_SES(state(j,2),state(j,12),evt_type); else new_state = evt_impact(state(j,2),evt_type); end %age incremented new_age= state(j,1)+1; %concatenation of the new state state(j,1)=new_age; state(j,2)=new_state; elseif ( state(j,11) ~= 0 ) % new widow stay depressed for one year state(j,11)=0; % the year of widow depression is over state(j,1)=state(j,1)+1; % age is updated end %*************************************************** end end %% %*********************************************************** %Social contact (evt_type) %*********************************************************** %****************************************************** %@pre: state_vec is the vector with all the variables of one individual %@post: Given the DS, a prob_plan (dep or non_dep) is selected % The age and the age_path enable to select the correct columns and % the probabilities defined in prob_plan % for singles % ----------- % prob_plan_dep_single and prob_plan_non_dep_single (4x4) % are used % single must have same widowing age then moving age % age_cat 1 is before_retiring till moving % age_cat 2 is after moving % age_cat 3 is after functional decline % age_cat 4 is after institutionalization % % for married % ----------- % Only the 1st columns of prob_plan_dep and prob_plan_non_dep (5x5) % is used: only age_cat 1 is valid % % for widows % ----------- % prob_plan_dep and prob_plan_non_dep (5x5) % are used % age_cat 1 is before_retiring till becoming widow % age_cat 2 is after becoming widow % age_cat 3 is after moving % age_cat 4 is after functional decline % age_cat 5 is after institutionalization % % % An evt_type (social contact) is generated: % 1= Spouse % 2= Friends & Kids % 3= Caregiver % 4= Neighbor % 5= No contact %****************************************************** function evt_type = evt_selection(state_vec) %global_parameters global prob_plan_non_dep global prob_plan_dep global prob_plan_dep_single global prob_plan_non_dep_single switch state_vec(1,9) %************************************************************************************ %single case 0 %nb : prob_plan_dep_single and prob_plan_non dep_single are 4x4) %check if (state_vec (1,1)>58 && state_vec(1,4)~=state_vec (1,5)) disp('error: single do not have same widowing age then moving age') pause end %************************************ age_path=state_vec(3:7); %************************************ %vicious circle effect if state_vec(2)==-1 prob_plan=prob_plan_dep_single; else prob_plan=prob_plan_non_dep_single; end; %************************************ temp_age=state_vec(1); if temp_age < age_path(2) %=>(temp_age < age_path(3)) age_cat=1; elseif temp_age < age_path(4) age_cat=2; elseif temp_age < age_path(5) age_cat=3; else age_cat=4; end %save the probabilities related the given category y1=prob_plan(1,age_cat); y2=prob_plan(2,age_cat); y3=prob_plan(3,age_cat); y4=prob_plan(4,age_cat); %y5=prob_plan(5,age_cat); %random generation temp_rand= rand*100; %assignement following probabilities % if temp_rand < y1 % evt_type=1; if temp_rand < y1 evt_type=2; elseif temp_rand < y1+y2 evt_type=3; elseif temp_rand < y1+y2+y3 evt_type=4; else evt_type=5; end %married case 1 %************************************ %vicious circle effect if state_vec(2)==-1 prob_plan=prob_plan_dep; else prob_plan=prob_plan_non_dep; end; %************************************ % Only the 1st columns of prob_plan_dep and prob_plan_non_dep (5x5) % is used: only age_cat 1 is valid y1=prob_plan(1,1); y2=prob_plan(2,1); y3=prob_plan(3,1); y4=prob_plan(4,1); y5=prob_plan(5,1); %random generation temp_rand= rand*100; %assignement following probabilities if temp_rand < y1 evt_type=1; elseif temp_rand < y1+y2 evt_type=2; elseif temp_rand < y1+y2+y3 evt_type=3; elseif temp_rand < y1+y2+y3+y4 evt_type=4; else evt_type=5; end %widow case 2 %*age cat 1 should neve be reached age_path=state_vec(3:7); %************************************ %vicious circle effect if state_vec(2)==-1 prob_plan=prob_plan_dep; else prob_plan=prob_plan_non_dep; end; %************************************ % check age of the individual, assign age category % age_cat 1 is before_retiring till becoming widow % age_cat 2 is after becoming widow % age_cat 3 is after moving % age_cat 4 is after functional decline % age_cat 5 is after institutionalization temp_age=state_vec(1); if temp_age < age_path(2) age_cat=1; elseif temp_age < age_path(3) age_cat=2; elseif temp_age < age_path(4) age_cat=3; elseif temp_age < age_path(5) age_cat=4; else age_cat=5; end %save the probabilities related the given category y1=prob_plan(1,age_cat); y2=prob_plan(2,age_cat); y3=prob_plan(3,age_cat); y4=prob_plan(4,age_cat); y5=prob_plan(5,age_cat); %random generation temp_rand= rand*100; %assignement following probabilities if temp_rand < y1 evt_type=1; elseif temp_rand < y1+y2 evt_type=2; elseif temp_rand < y1+y2+y3 evt_type=3; elseif temp_rand < y1+y2+y3+y4 evt_type=4; else evt_type=5; end end %end switch end %*********************************************************** %Impact selection (evt_impact) %*********************************************************** %% %*************************************************** %@ pre: evt_type is the social contact previously computed in evt_selection % current_state is the current DS of the individual % prob_impact_unit is the Impact Table with % probabilities of impact on dep (-1,0,+1) % depedning on the social contact % 1= Spouse % 2= Friends & Kids % 3= Caregiver % 4= Neighbor % 5= No contact %@ post: given the probabilities defined in prob_impact_unit for the given % evt_type (social contact), an impact is generated. % This impact is added to the current state new_state. % If the new state is beyond the limits (-2,+2) it is set back to % (-1,+1) %*************************************************** function new_state= evt_impact(current_state,evt_type) global prob_impact_unit %impact probability matrix %depression state %---------------- temp_rand= rand*100; if temp_rand< prob_impact_unit(1,evt_type) new_state = current_state-1; elseif temp_rand< prob_impact_unit(1,evt_type)+prob_impact_unit(2,evt_type) new_state = current_state; else new_state = current_state+1; end % adjust if we went beyond the limits if new_state==2 new_state=1; elseif new_state==-2 new_state=-1; end end %% %*************************************************** %@ pre: evt_type is the social contact previously computed in evt_selection % current_state is the current DS of the individual % prob_impact_unit is the Impact Table with % probabilities of impact on dep (-1,0,+1) % depedning on the social contact % 1= Spouse % 2= Friends & Kids % 3= Caregiver % 4= Neighbor % 5= No contact % SES indicates a distinction on the SES : % 1 => disadvantaged % 0 => others %@ post: Given SES one the impact table: % - prob_impact_unit (SES=0) % - prob_impact_unit_dis (SES=1) % is selected % given the probabilities defined in prob_impact_unit and % global prob_impact_unit_dis for the given evt_type (social % contact), an impact is generated. % This impact is added to the current state new_state. % If the new state is beyond the limits (-2,+2) it is set back to % (-1,+1) %*************************************************** function new_state= evt_impact_SES(current_state,SES, evt_type) global prob_impact_unit %impact probability matrix global prob_impact_unit_dis %impact probability matrix for def people %depression state %---------------- temp_rand= rand*100; %if disadvantaged if SES==1 prob_selected=prob_impact_unit_dis; else prob_selected=prob_impact_unit; end if temp_rand< prob_selected(1,evt_type) new_state = current_state-1; elseif temp_rand< prob_selected(1,evt_type)+prob_selected(2,evt_type) new_state = current_state; else new_state = current_state+1; end % adjust if we went beyond the limits if new_state==2 new_state=1; elseif new_state==-2 new_state=-1; end end %*********************************************************** %variable generation %*********************************************************** %% %% %*************************************************** % @ pre: mu is the mean age around which we want the generate the random % age, std is a standard deviation of a normal noise and prev % is the life of the previous events that has already been generated. % @ post: a random age is generated around mu with normal noise std. % if the randomization inverts the age (random_age<= prev) % the new age for the new event is set to prev+1 %*************************************************** function random_age = generate_age (mu,std,prev) random_age = round(random('Normal',mu,std)); if random_age<= prev random_age=prev+1; end end %% %*************************************************** % @ pre: % @ post: a random gender is generated based on the probability % gender_rate (%women) % 1 male % 0 female %*************************************************** function random_sex = generate_sex global gender_rate % female prob if rand < gender_rate random_sex= 0; else random_sex= 1; end end %% %*************************************************** % @ pre: the sex of the individuals has been set % @ post: ofr individuals of min_age (61) % depending on the sex a random DS is generated % based on the probabilities rate_dep_m or rate_dep_f % (percentage of depressed => DS=-1) % the other are set either to DS= 0 or DS= +1 with equal chance %*************************************************** function random_DS = generate_DS(sex) global rate_dep_m global rate_dep_f %for female if sex==0 if rand < rate_dep_f random_DS= -1; else %if not depressed, equal chances to be 0 or +1 random_DS= randi(2)-1; end %for male else if rand < rate_dep_m random_DS= -1; else %if not depressed, equal chances to be 0 or +1 random_DS= randi(2)-1; end end end %************************************************************************* %Birth +wedding+die+ update path %************************************************************************* %% %*************************************************** % @ pre: new_birth is the number of elderly to add each year to the % population % @ post: new_birth people are added to the population with age 61, % with neutral DS % age_path is not defined yet only the first age is set an the % other items are set up to max_age % (only the first column 'retired' is to be used %*************************************************** function birth = gen_birth(new_birth) global min_age global max_age global eld_var_num global age_path global age_std global check_SES birth= zeros(new_birth, eld_var_num); %for each agent for i=1:new_birth %age and functional_status birth(i,1)=min_age;%everybody is min_age years olds birth(i,8)= generate_sex; birth(i,2)= generate_DS(birth(i,8)); birth(i,3)= generate_age (age_path(1,1),age_std,min_age); birth(i,4)= max_age; birth(i,5)= max_age; birth(i,6)= max_age; birth(i,7)= max_age; if check_SES==1 birth(i,12)=generate_SES; end end end %% %*************************************************** % @ pre: state is the population at the beginning of the iteration % delta_dead (29x1) holds the delta of person to retrieve % by age (65:93) in order to fit the empirical mortality rate % (see function die_delta_dead) % @ post: for each age (65:92) the corresponding delta of individuals % is selected at random and are retrieved % people aged of 93 years are also retrieved % The case of married people dying creates widows who are treated % by the function become_widow % Once individuals retrieved, binding between wives and husbands % need to me update by the function rewiring. %*************************************************** function state= die(state, delta_dead) global max_age [a,b]=size(state); [c,d]=size(delta_dead); for i=1:c-1 % each ages but the last age (max_age) Ages_indices = find(state(:,1)==delta_dead(i,1)); % check that there actually is people of this age if size(Ages_indices) ~= [0,0] % if delta is positive remove extra % elderly to obtain correct number of respondent if delta_dead(i,2) > 0 indices_to_remove=[]; indices_to_remove=[indices_to_remove, randsample(Ages_indices', delta_dead(i,2))]; % index selected twice check_table= tabulate(indices_to_remove); if max(check_table(:,2))>=2 disp('error: max(check_table)>=2') pause end if ~isempty(indices_to_remove) state= become_widow(state, indices_to_remove); [state ps] = removerows( state,indices_to_remove); state= rewiring(state, ps.recreate_ind); %update indices for married people consistency end end end end %consider natural death now natural_death = find(state(:,1)==max_age)'; if ~isempty(natural_death) state= become_widow(state, natural_death); [state ps] = removerows(state,natural_death); state= rewiring(state, ps.recreate_ind); %update indices for married people consistency end end %% %*************************************************** %@pre state has just been added new_birth elderly with min_age(61) years old elderly % not married % %@post : single women of min_age(61) years old are married with single men % of min_age_male_wedding(62) or max_age_male_wedding(63) years old %nb called after gen_birth,...in routine (once higher (62-63) age have members) %*************************************************** function state= wedding(state) global min_age global min_age_male_wedding global max_age_male_wedding global rate_married_women %new created female of min_age(61) and single female_single_indices= find(state(:,1)==min_age & state(:,8)==0 & state(:,9)==0); num_women_to_marry=round(size(female_single_indices,1)*rate_married_women); %special case for low number of elderly and only 1 women is to be %married %regular case for several women are available to be married if size(female_single_indices,1)>1 female_single_indices= randsample(female_single_indices, num_women_to_marry); end % we select the women to marry (the other will remain singles) %male not married (=> not matched) between min_age_male_wedding and max_age_male_wedding (56 or 57) male_single_indices= find((state(:,1)>=min_age_male_wedding & state(:,1)<= max_age_male_wedding) & state(:,8)==1 & state(:,9)==0 & state(:,10)==0); a=size(female_single_indices); b=size(male_single_indices); num_wedding=min(a,b); %for each women for i=1:num_wedding woman=female_single_indices(i); man= male_single_indices(i); %they get married and associated to each other state(woman,9)=1; state(man,9)=1; state(woman,10)=man; state(man,10)=woman ; end end %% %*************************************************** %@pre: prob_plan is prob_plan_dep or prob_plan_non_dep (5x5) matrix % %@post: the prob plan specific to singles is generated where the influence %of the spouse is cancele %nb= must be ran on prob_plan_dep AND prob_plan_non_dep %*************************************************** function new_prob_plan = prob_plan_for_single (prob_plan) [a,b]=size(prob_plan); new_prob_plan=[]; %for each column for i=[1,3:b] new_tot=sum(prob_plan(2:5,i)); new_prob_plan=[new_prob_plan (prob_plan(2:5,i)./new_tot)*100]; end end %% %*************************************************** %@pre: given a list of dying people not retrieved yet % if they are married % the dying spouse has not been retrieved yet %@post : 1) we turn their spouse into widow (state(., 9)=2, % 2) their state becomes depressed ) % 3) their Historic Variable is set to one so that the new widow % will remain depressed for one year % 4)age path is updated wiht current age set as age of widowhood % other ages are generated %*************************************************** function state= become_widow(state, index_dying_spouse) global age_path global age_std [a,b]=size(index_dying_spouse); %nb, the case when the widow dies as well % is not specifically treated as he dies too %for each dying individuals for i=1:b %if he/she's indeed married if state(index_dying_spouse(i),9)==1 spouse=state(index_dying_spouse(i),10); state(spouse,2)=-1; % DS is set to depressed state(spouse,9)=2; % marital status is set to widow state(spouse,10)=0; % connection to old partner is cancelled state(spouse,11)=1; % will remain depressed for one year %age path of the spouse is updated %age of widowhood is set to current age state(spouse,4)= state(spouse,1); % if possible we stick with the normal chain of events if state(spouse,4) <= age_path(1,2) state(spouse,5)= generate_age (age_path(1,3),age_std,state(spouse,4)); state(spouse,6)= generate_age (age_path(1,4),age_std,state(spouse,5)); state(spouse,7)= generate_age (age_path(1,5),age_std,state(spouse,6)); %else the 3 remaining events are sparsed till the end of life %preserving decay between events else state(spouse,5)= state(spouse,4)+randi(5,1); state(spouse,6)= state(spouse,5)+randi(5,1); state(spouse,7)= state(spouse,6)+randi(2,1); end end end end %% %*************************************************** %@pre : state hold elderly married and single % everybody older than global max_age_male_wedding is either % - single until he dies % - married and will become widow (men or women) %@post: the age path of single eldelry older than max_age_male_wedding is % set : % Random ages for moving, functional decline and % institutionalization are generated with a normal distribution around mean % ages (75,80,82) and with standard deviation = 2 that induces a % relative variation for illustrative purpose (update_age_path.m) %*************************************************** function state = update_age_path(state) global max_age_male_wedding global age_path global age_std %find single male and female of max_age_wedding years old I=find(state(:,1)==max_age_male_wedding+1 & state(:,9)==0); [a,b]=size(I); %nb= I is a column vector %for each agent for i=1:a % birth(i,3) ( ge of retirement has already been set) is already set % caution here age_path of single have to comply with the fact that they do not encounter widowhood % Age of widowhood is the same than age of moving state(I(i,1),5)= generate_age (age_path(1,3),age_std,age_path(1,1)); state(I(i,1),4)= state(I(i,1),5); %=> do not encounter widowhood! state(I(i,1),6)= generate_age (age_path(1,4),age_std,state(I(i,1),5)); state(I(i,1),7)= generate_age (age_path(1,5),age_std,state(I(i,1),6)); end end %*********************************************************************** %treatment case %*********************************************************************** %% %*************************************************** % @ pre: state is the result of the initial individual on the population % after one year (iteration). The new born elderly havent' been added yet % @ post: a proportion treatment_rate of % the population with DS=-1 is treated: % - half of them are updated to a DS= 0; % - the other half are updated to a DS= 1 %*************************************************** function state= treatment(state) global treatment_rate I=find(state(:,2)==-1); [a,b]= size(I); number_to_treat= round(a*treatment_rate); I= randsample(I,number_to_treat); [a,b]= size(I); for i= 1:a state(I(i),2)=randi(2)-1; % 0 or +1 with probability 50% end end %*********************************************************************** %SES case %*********************************************************************** %% %*************************************************** % @ pre: prob_impact_unit is the initial impact table % @ post: an impact table prob_impact_unit_dis is created % for disadvantaged people where a ratio prop_dispatch_SES % of the null and positive impact probabilities are transfered % on the negative impact probabilitiy %*************************************************** function prob_impact_unit_dis = generate_prob_impact_unit_SES(prob_impact_unit) global prop_dispatch_SES prob_impact_unit_dis=zeros(3,5); a=prob_impact_unit(3,:)/prop_dispatch_SES; b=prob_impact_unit(2,:)/prop_dispatch_SES; prob_impact_unit_dis(3,:)=prob_impact_unit(3,:)-a; prob_impact_unit_dis(2,:)=prob_impact_unit(2,:)-b; prob_impact_unit_dis(1,:)=prob_impact_unit(1,:)+a+b; if sum(prob_impact_unit_dis)~=100*ones(1,5) disp('prob_impact_init inconsistent') end end %% %*************************************************** % @ pre: state has been generated % @ post: generate an socio-economic status at random % 0 no consideration of SES % 1consideration of SES %*************************************************** function random_SES = generate_SES global disadvantagedSES_rate % probability of being disadvantage if rand < disadvantagedSES_rate random_SES= 1; else random_SES= 0; end end %*********************************************************************** %Technical Utility %*********************************************************************** %% %*************************************************** % @ pre: state has been generated % @ post: compute the number of -1, 0 ,+1 % in the population (state) %*************************************************** function [m1 z0 p1] = get_n(state) %compute the number of -1, 0 ,+1 in the population state global min_age global max_age m1=histc(state(state(:,2)==-1,1),min_age:max_age)'; z0=histc(state(state(:,2)==0,1),min_age:max_age)'; p1=histc(state(state(:,2)==1,1),min_age:max_age)'; end %% %*************************************************** %@pre: state has just been removed dying people % new widow have been already set widow by % become_widow (marital status=2) % people with marital status maried need % to be rewired has indices changed % ps.recreate_ind as been retrieved from removerows, % remove people to die %@post : all married people are matched again %*************************************************** function state= rewiring(state, recreate_ind) %only those who are married I= find(state(:,9)==1); [a,b]=size(I); %for each married person for i=1:a %the index of his spouse % is found and assigned state(I(i),10)= recreate_ind(state(I(i),10)); end end %*********************************************************************** %Empirical data %*********************************************************************** %% %*************************************************** % @ pre: empirical data have been retrieved for years 2001-2004-2008 %http://economie.fgov.be/fr/modules/publications/statistiques/population/ta %bles_de_mortalite.jsp % With columns, defined for men and women: % [px dx Qx] % (px) observed population % (dx) observed death % (Qx) death probability % for ages 65-92 % nb Qx= dx/px % % @ post: empirical data for 2001-2004-2008 are averaged and gathered in % mortalilty data for ages 65-92 %*************************************************** function mortality_data = retrieve_mortality pop_stat_2008 = [ %65 90748 1109 0.012221 82481 1110 0.013458 91407 1302 0.014244 98181 1510 0.015380 98903 1661 0.016794 94182 1662 0.017647 90932 1865 0.020510 88889 1938 0.021802 89153 2204 0.024722 87281 2384 0.027314 88592 2696 0.030432 86577 3002 0.034674 84009 3254 0.038734 75611 3269 0.043234 71567 3662 0.051169 66301 3567 0.053800 62861 3913 0.062248 59421 4162 0.070043 54153 4307 0.079534 49297 4363 0.088504 43472 4371 0.100547 38874 4326 0.111283 33416 4205 0.125838 21752 3066 0.140953 12929 2010 0.155464 10612 1759 0.165756 9706 1828 0.188337 9380 1941 0.206930 ]; pop_stat_2004 = [ 104671 1338 0.012783 99931 1291 0.012919 97065 1419 0.014619 95695 1556 0.016260 96605 1696 0.017556 95585 1872 0.019585 98060 2154 0.021966 96943 2448 0.025252 95391 2723 0.028546 87183 2621 0.030063 83731 2911 0.034766 79428 3102 0.039054 76840 3305 0.043011 74505 3633 0.048762 69850 3735 0.053472 65774 3983 0.060556 59909 4033 0.067319 56156 4283 0.076270 50789 4320 0.085058 34552 3208 0.092846 21910 2336 0.106618 19001 2268 0.119362 18751 2478 0.132153 19504 2859 0.146585 19432 3101 0.159582 15891 2821 0.177522 12715 2480 0.195045 9522 2122 0.222852 ]; pop_stat_2001 = [ %65 100062 1357 0.013562 101415 1501 0.014801 100851 1660 0.016460 104144 1905 0.018292 103508 2023 0.019544 102331 2308 0.022554 94565 2276 0.024068 91636 2514 0.027435 87761 2546 0.029011 86144 2832 0.032875 84435 3050 0.036122 80628 3344 0.041474 76884 3520 0.045783 71469 3660 0.051211 68549 3872 0.056485 63797 4083 0.064000 44678 3223 0.072138 28971 2269 0.078320 26269 2319 0.088279 26948 2711 0.100601 29156 3235 0.110955 30251 3652 0.120723 26285 3529 0.134259 22274 3468 0.155697 17914 2995 0.167188 14825 2745 0.185160 11457 2249 0.196299 9411 2025 0.215174 ]; u=cat(3,pop_stat_2001,pop_stat_2004,pop_stat_2008); mortality_data=sum(u,3); mortality_data(:,3)= mortality_data(:,2)./mortality_data(:,1); end %% %% %*************************************************** %@pre : Mortality_data. m retrieve the empirical mortality rate % retrieve %@post: delta_dead has been generated % with the number of number of respondents between % 65 and 92 years old % => at 93 the number of respondent is set to let everybody die) %*************************************************** function delta_dead = die_delta_dead (initial_pop_size) XI=[65:93]' ; YI=compute_artificial_pop(initial_pop_size)'; ZI=[]; %die each year for i =1: size(YI,1)-1 ZI=[ZI; YI(i)-YI(i+1)]; end ZI=[ZI; YI(size(YI,1),1)]; delta_dead=[XI ZI]; end %% %*************************************************** % @ pre: pop_size is the size of the population we want to mimic % @ post: a population size evluation reflecting real (mean) mortality % rate (see retrieve mortality) is returned for ages 65-92 %*************************************************** function artificial_pop= compute_artificial_pop(pop_size) mortality_data = retrieve_mortality; [a,b]=size(mortality_data); artificial_pop=[pop_size]; for i=1:a pop_size=pop_size - round(pop_size*mortality_data(i,3)); artificial_pop=[artificial_pop pop_size] ; end end %******************************************************* %drawing %******************************************************* %% %*************************************************** % @ pre: % @ post: the empirical mean prevalence and its CI is % drawn in dashed line from ages 65 to 92 %*************************************************** function draw_empirical_filigrane [A prevallyears nallyears CI_low CI_high]= load_empirical_data; plotall=plot(1:28,A(:,prevallyears),'k--'); %1:28 => 65-92 from 65 set(plotall,'LineWidth',1); hold on plotmin=plot(1:28,A(:,CI_low),'k--'); set(plotmin,'LineWidth',1); plotmax=plot(1:28,A(:,CI_high),'k--'); set(plotmax,'LineWidth',1); end %% %*************************************************** % @ pre: prev_m1 are the prevalence by age gathered through all simulation % prev_m1 is 32 columns (61:92) % and the number of rows is the number of simulations. % @ post: the plot with the simulated data is drawn %*************************************************** function [ploti prev_m1]= draw_one_plot(prev_m1) prev_m1=mean(prev_m1(:,5:32),1); %5:32=> 65-92 from 65 on (61(age) = 1(index)) ploti=plot(1:28,prev_m1); set(ploti,'LineWidth',2); BOX OFF xlim([1 29]); set(gca,'FontSize',16,'Xtick',[1:5:29],'XtickLabel',['65';'70';'75';'80';'85';'90';'95']); set(gca,'FontSize',16); ylabel('Prevalence depressison (%)','FontSize',16); xlabel('Age','FontSize',16); end %% %*************************************************** % @ pre: % @ post: draw the regression line %*************************************************** %plot the empirical regression function h= draw_regression; X=regressed_prev; h= plot(X); end %*************************************************** % @ pre: % @ post: Empirical prevalences of depression % retrieved from HIS are saved in matrix A % prevallyears =1st column is the prevalence by year; % nallyears = the 2nd column total number of respondents; % CI_low = the 3rd column is the lower bound of the CI; % CI_high = the 3rd column is the upperd bound of the CI; %*************************************************** function [A prevallyears nallyears CI_low CI_high]= load_empirical_data prevallyears =1; nallyears = 2; CI_low = 3; CI_high = 4; A=[ 8.2 333 3.1 13.2 9.5 335 5.4 13.5 8.7 316 4.7 12.7 10.5 312 5.9 15.0 12.1 315 7.1 17.2 10.9 315 6.2 15.6 18.2 294 6.2 30.1 12.6 311 8.1 17.1 12.7 280 7.7 17.6 16.1 266 9.9 22.2 10.6 264 5.3 15.9 7.9 250 3.8 12.1 8.8 225 4.7 13.0 10.6 210 5.8 15.4 21 195 11.8 30.2 12.5 213 7.1 17.9 15 153 6.6 23.3 13.7 157 6.4 21.0 12.3 133 6.3 18.3 15.9 178 9.6 22.2 20.2 225 12.1 28.3 18.4 205 8.1 28.7 14.7 188 7.7 21.7 17.3 161 9.6 25.0 18.1 107 8.9 27.3 16.3 79 4.2 28.4 11.2 70 0.6 21.8 10.1 54 1.4 18.9 ]; %************************************************* end %******************************************************* % Stat test and numerical test %******************************************************* %% %*************************************************** % @ pre: sim_curve are the last iterations of multiple simulations % representin the simulated prevalence of(by lines) % @ post: The following statistics and information are computed: % - Wilcoxon signed rank test for zero median (P,H) % two-sided test of the hypothesis that the difference between % the matched samples in the vectors X and Y % comes from a distribution whose median is zero % P is the probability of observing the given result, or one more % extreme, by chance if the null hypothesis ("median is zero") is true. % H=0 indicates that the null hypothesis ("median is zero") % cannot be rejected at the 5% level. % H=1 indicates that the null hypothesis can be rejected at the % 5% level. % - ks test with regression line [H,P,KSSTAT] % H = 0 => Do not reject the null hypothesis at significance level 5%. % H = 1 => Reject the null hypothesis at significance level 5%. % P=asymptotic P-value % K-S= test statistic % - correlation coefficient with regression line %*************************************************** function TS = compute_TS(Sim_curves) prev_m1=mean(Sim_curves(:,5:32),1); %5:32=> 65-92 from 65 on (61(age) = 1(index)) [A prevallyears nallyears CI_low CI_high]=load_empirical_data; empirical_curve= A(:,prevallyears); % Wilcoxon signed rank test for zero median. %(p-value and H=1 indicates that the null hypothesis can be rejected at the %5% level [P H]=signrank(prev_m1,empirical_curve); %signed_rank TS=[P H]; X=regressed_prev; %ks test with regression line [H,P,KSSTAT]=kstest2(prev_m1,X); TS=[TS [H,P,KSSTAT]]; %correlation coefficient with regression line Rreg=corrcoef(prev_m1,X); TS=[TS Rreg(1,2)]; end %% %*************************************************** % @ pre: sim_curve are the last iterations of multiple simulations % representin the simulated prevalence of(by lines) % @ post: compute the number of occurences of the mean of the % simulated curves falling within the CI bounds (between 65 and 92) %*************************************************** function within_CI = compute_Num_index(Sim_curves) prev_m1=mean(Sim_curves(:,5:32),1)'; %5:32=> 65-92 from 65 on (61(age) = 1(index)) [A prevallyears nallyears CI_low CI_high]=load_empirical_data; %how many time within the interval I=find(prev_m1(:,1)<= A(:,CI_high) & prev_m1(:,1)>=A(:,CI_low)); within_CI=size(I,1); end %******************************************************* % Regresssion %******************************************************* %% %*************************************************** % @ pre: % @ post: compute the regression line on the empirical % prevalnence %*************************************************** function X=regressed_prev [A prevallyears nallyears CI_low CI_high]= load_empirical_data; [a,b]=size(A); H=regress(A(:,1),[[1:a]' ones(a,1)]); X=(H(1,1)*[1:a]') + H(2,1); end %************************************************************************************** %Simulation_RBM_eld_dep_no_wed.m %************************************************************************************** %*********************************************************************** % Rule-based simulation of elderly depression % considering *NO* gender distinction and *NO* wedding procedure %*********************************************************************** %@author: Jean-Christophe %@date : 04/2012 % % @pre: %------ % % WS_list: this list of indices represents the number % of times the simulation should be run. % ex: to run the simulation 50 enter the list 1:50 % WS_dir: directory where to save the .mat files generated for each % simulations % Prefix: Prefix of the name of the .mat files generated for each % simulations % % nb: - the parameters of the simualtion are defined % in the parameters.m file (scenario parameters, % selection of a typology of experts, size of the population,...) % - the experts'answers of each typology are saved in specific .m files % ex: param_typeA.m (for expert of Type A) % % @post: %---------- % The parameters of parameters.m are loaded. % The parameters of the typology of experts requested % in parameters.m are loaded % % Multiple simulation are generated for one scenario and one type of % experts, considering *NO* gender distinction and *NO* wedding procedure % For each simulation a Workspace with all the relevant information is saved % in WSdir with name Prefix_typex_y.mat where x refers to the typology of % experts and y the number of iterations. THis workspace records: % - values of the parameters, Contact and Impact tables % - scenario info (check_treatment, check_SES) % - prevalences of the last iterations of the simulation (myprev_m1) % - indices of fit computes by functions compute_TS and % compute_Num_index(see their specifications). % - other variables are only technique variables % For each simulation the prevalences of the current simulation are saved % and accumulated in variable myprev_m1. % These saved prevalences are then averaged and the mean is % drawn together with the empirical prevalences retrieved % from The online Belgian Health Interview Survey (HIS) % and the associated regression line. % % @example: %---------- % To run 50 simulations and save your 50 workspaces % in the directory '/Users/Desktop/test' % with prefix of name 'My_simulation' % use the following command % % [myprev_m1]= ... % Simulation_RBM_eld_dep_no_wed(1:50, '/Users/Desktop/test',... % 'My_simulation'); % % myprev_m1 holds the prevalences by age of the last iterations of % 50 simulations %*********************************************************** %Multiple Simulations %*********************************************************** function myprev_m1= Simulation_RBM_eld_dep_no_wed(WS_list, WS_dir, prefix) global n_m1 global n_z0 global n_p1 global prob_impact_unit global prob_plan_non_dep global prob_plan_dep global type global check_treatment global check_SES % 0 no consideration of SES % 1consideration of SES %**************************** %parameters & expert answers %**************************** parameters myparam=strcat('param_Type',type); [prob_impact_unit prob_plan_non_dep prob_plan_dep] =eval(myparam); %**************************** %simulations %**************************** [a,b]=size(WS_list); myprev_m1=[]; % prevalences of depression by age for my_it=1:b ext=num2str(WS_list(1,my_it)) %one simulation sim_process_no_wedding; %save the current prevalence n_tot=n_m1+n_p1+n_z0; prev_m1= (n_m1./n_tot)*100; myprev_m1=[myprev_m1; prev_m1]; %save WS in the right directory for analysis process_dir=pwd; cd(WS_dir); my_prefix= strcat(prefix,'_type',type,'_'); WS_file=strcat(my_prefix,ext); save (WS_file); cd(process_dir); end %**************************** %drawing %**************************** close all draw_empirical_filigrane; draw_one_plot(myprev_m1); draw_regression; %**************************** %stat %**************************** TS = compute_TS(myprev_m1); within_CI = compute_Num_index(myprev_m1); fit_index = [within_CI TS] end %*********************************************************** %One Simulation %*********************************************************** %% %****************************************************** %@pre: parameters have been loaded (parameters.m) %@post: one simulation (W wedding procedure) % - an initial population is created % - each individuals goes through an individual process % - a treatment effect may be applied to the population % (check_treatment=1) % - new individuals are added to the population % - they die at the beginning of the next iteration %****************************************************** function sim_process_no_wedding %********************** %Data structure %********************** global n_m1 % number of depressed DS global n_z0 % number of neutral DS global n_p1 % number of non-depressed DS global state % variable (columns) for each individual (row) global num_eld global new_birth global num_it global eld_var_num global prob_impact_unit global prob_impact_unit_dis %SES global check_treatment global check_SES %********************** %Initiatlization %********************** %[sex,depression state; age_path; sex; marita_status; %spouse_index; widow_history; SES]; if check_SES==1 eld_var_num=12; else %[sex,depression state; age_path; sex; marita_status; %spouse_index; widow_history]; eld_var_num=11; end %nb:[sex; marita_status; spouse_index; widow_history] are not used here %SES consideration generationt of a specific prob_impact if check_SES==1 prob_impact_unit_dis=generate_prob_impact_unit_SES(prob_impact_unit); end %data for dying process delta_dead = die_delta_dead (num_eld); %initial_population state = gen_birth(num_eld); %********************** %Iterative process %********************** for current_it =1:num_it %each year %display if mod(current_it,5)==0 current_it end %dying process (remove indiviudual subsequently to fit empirical mortality %rate between 65 and 92) %natural death is retrieved here state= die(state, delta_dead); %Individual process state = individual_process(state); %treatment if check_treatment==1 state=treatment(state); end %birth process birth = gen_birth(new_birth); state=[state;birth]; clear birth end %******************************** %prevalence and demographic stat %******************************** %demographic stat population=[current_it size(state,1) histc(state(:,8),0:1)' histc(state(:,9),0:2)']; %prevalence computation [n_m1 n_z0 n_p1] = get_n(state); end %*************************************************** %Individual process %*************************************************** %% %****************************************************** %@pre: state is a matrix with the all population %@post: each individual is processed (for one year): % - a contact with a source of social support is selecte (evt_type) % - an impact is selected possibly integrating a SES distinction % (check_SES=1) % - the age incremented %****************************************************** function state = individual_process(state) global check_SES [a,b]=size(state); % a= number of elderly persons % b= num-of variables for j = 1: a % for each individu still alive %select evt type evt_type = evt_selection(state(j,:)); %given evt type compute the impact for an individual if check_SES==1 new_state = evt_impact_SES(state(j,2),state(j,12),evt_type); else new_state = evt_impact(state(j,2),evt_type); end %age incremented new_age= state(j,1)+1; %concatenation of the new state state(j,1)=new_age; state(j,2)=new_state; end end %% %*********************************************************** %Social contact (evt_type) %*********************************************************** %****************************************************** %@pre: state_vec is the vector with all the variables of one individual %@post: Given the DS, a prob_plan (dep or non_dep) is selected % The age and the age_path enable to select the correct columns and % the probabilities defined in prob_plan for the given % and an evt_type (social contact) is generated: % 1= Spouse % 2= Friends & Kids % 3= Caregiver % 4= Neighbor % 5= No contact %****************************************************** function evt_type = evt_selection(state_vec) %global_parameters global prob_plan_non_dep global prob_plan_dep global age_path %************************************ %vicious circle effect if state_vec(2)==-1 prob_plan=prob_plan_dep; else prob_plan=prob_plan_non_dep; end; %************************************ % check age of the individual, assign age category temp_age=state_vec(1); if temp_age < age_path(2) age_cat=1; elseif temp_age < age_path(3) age_cat=2; elseif temp_age < age_path(4) age_cat=3; elseif temp_age < age_path(5) age_cat=4; else age_cat=5; end %save the probabilities related the given category y1=prob_plan(1,age_cat); y2=prob_plan(2,age_cat); y3=prob_plan(3,age_cat); y4=prob_plan(4,age_cat); y5=prob_plan(5,age_cat); %random generation temp_rand= rand*100; %assignement following probabilities if temp_rand < y1 evt_type=1; elseif temp_rand < y1+y2 evt_type=2; elseif temp_rand < y1+y2+y3 evt_type=3; elseif temp_rand < y1+y2+y3+y4 evt_type=4; else evt_type=5; end end %*********************************************************** %Impact selection (evt_impact) %*********************************************************** %% %*************************************************** %@ pre: evt_type is the social contact previously computed in evt_selection % current_state is the current DS of the individual % prob_impact_unit is the Impact Table with % probabilities of impact on dep (-1,0,+1) % depedning on the social contact % 1= Spouse % 2= Friends & Kids % 3= Caregiver % 4= Neighbor % 5= No contact %@ post: given the probabilities defined in prob_impact_unit for the given % evt_type (social contact), an impact is generated. % This impact is added to the current state new_state. % If the new state is beyond the limits (-2,+2) it is set back to % (-1,+1) %*************************************************** function new_state= evt_impact(current_state,evt_type) global prob_impact_unit %impact probability matrix %depression state %---------------- temp_rand= rand*100; if temp_rand< prob_impact_unit(1,evt_type) new_state = current_state-1; elseif temp_rand< prob_impact_unit(1,evt_type)+prob_impact_unit(2,evt_type) new_state = current_state; else new_state = current_state+1; end % adjust if we went beyond the limits if new_state==2 new_state=1; elseif new_state==-2 new_state=-1; end end %% %*************************************************** %@ pre: evt_type is the social contact previously computed in evt_selection % current_state is the current DS of the individual % prob_impact_unit is the Impact Table with % probabilities of impact on dep (-1,0,+1) % depedning on the social contact % 1= Spouse % 2= Friends & Kids % 3= Caregiver % 4= Neighbor % 5= No contact % SES indicates a distinction on the SES : % 1 => disadvantaged % 0 => others %@ post: Given SES one the impact table: % - prob_impact_unit (SES=0) % - prob_impact_unit_dis (SES=1) % is selected % given the probabilities defined in prob_impact_unit and % global prob_impact_unit_dis for the given evt_type (social % contact), an impact is generated. % This impact is added to the current state new_state. % If the new state is beyond the limits (-2,+2) it is set back to % (-1,+1) %*************************************************** function new_state= evt_impact_SES(current_state,SES, evt_type) global prob_impact_unit %impact probability matrix global prob_impact_unit_dis %impact probability matrix for def people %depression state %---------------- temp_rand= rand*100; if SES==1 prob_selected=prob_impact_unit_dis; else prob_selected=prob_impact_unit; end if temp_rand< prob_selected(1,evt_type) new_state = current_state-1; elseif temp_rand< prob_selected(1,evt_type)+prob_selected(2,evt_type) new_state = current_state; else new_state = current_state+1; end % adjust if we went beyond the limits if new_state==2 new_state=1; elseif new_state==-2 new_state=-1; end end %*********************************************************** %variable generation %*********************************************************** %% %*************************************************** % @ pre: mu is the mean age around which we want the generate the random % age, std is a standard deviation of a normal noise and prev % is the life of the previous events that has already been generated. % @ post: a random age is generated around mu with normal noise std. % if the randomization inverts the age (random_age<= prev) % the new age for the new event is set to prev+1 %*************************************************** function random_age = generate_age (mu,std,prev) random_age = round(random('Normal',mu,std)); if random_age<= prev random_age=prev+1; end end %************************************************************************* %Birth +die %************************************************************************* %% %*************************************************** % @ pre: new_birth is the number of elderly to add each year to the % population % @ post: new_birth people are added to the population with age 61, % with neutral DS and an age_path, generated by generate_age. %*************************************************** function birth = gen_birth(new_birth) global min_age global eld_var_num global age_path global age_std global check_SES birth= zeros(new_birth, eld_var_num); %for each agent for i=1:new_birth birth(i,1)=min_age;%everybody is min_age years olds birth(i,8)= 0; birth(i,2)= 0; birth(i,3)= generate_age (age_path(1,1),age_std,min_age); birth(i,4)= generate_age (age_path(1,2),age_std,birth(i,3)); birth(i,5)= generate_age (age_path(1,3),age_std,birth(i,4)); birth(i,6)= generate_age (age_path(1,4),age_std,birth(i,5)); birth(i,7)= generate_age (age_path(1,5),age_std,birth(i,6)); if check_SES==1 birth(i,12)=generate_SES; end end end %% %*************************************************** % @ pre: state is the population at the beginning of the iteration % delta_dead (29x1) holds the delta of person to retrieve % by age (65:93) in order to fit the empirical mortality rate % (see function die_delta_dead) % @ post: for each age (65:92) the corresponding delta of individuals % is selected at random and are retrieved % people aged of 93 years are also retrieved %*************************************************** function state= die(state, delta_dead) global max_age [a,b]=size(state); [c,d]=size(delta_dead); for i=1:c-1 % each ages but the last age (max_age) Ages_indices = find(state(:,1)==delta_dead(i,1)); % check that there actually is people of this age if size(Ages_indices) ~= [0,0] % if delta is positive remove extra elderly to obtain correct number of respondent if delta_dead(i,2) > 0 indices_to_remove=[]; indices_to_remove=[indices_to_remove, randsample(Ages_indices', delta_dead(i,2))]; % index selected twice check_table= tabulate(indices_to_remove); if max(check_table(:,2))>=2 disp('error: max(check_table)>=2') pause end if ~isempty(indices_to_remove) [state ps] = removerows( state,indices_to_remove); end end end end %consider natural death now natural_death = find(state(:,1)==max_age)'; if ~isempty(natural_death) [state ps] = removerows(state,natural_death); end end %*********************************************************************** %treatment case %*********************************************************************** %% %*************************************************** % @ pre: state is the result of the initial individual on the population % after one year (iteration). The new born elderly % havent' been added yet % @ post: a proportion treatment_rate of % the population with DS=-1 is treated: % - half of them are updated to a DS= 0; % - the other half are updated to a DS= 1 %*************************************************** function state= treatment(state) global treatment_rate I=find(state(:,2)==-1); [a,b]= size(I); number_to_treat= round(a*treatment_rate); I= randsample(I,number_to_treat); [a,b]= size(I); for i= 1:a state(I(i),2)=randi(2)-1; % 0 or +1 with probability 50% end end %*********************************************************************** %SES case %*********************************************************************** %% %*************************************************** % @ pre: prob_impact_unit is the initial impact table % @ post: an impact table prob_impact_unit_dis is created % for disadvantaged people where a ratio prop_dispatch_SES % of the null and positive impact probabilities are transfered % on the negative impact probabilitiy %*************************************************** function prob_impact_unit_dis = generate_prob_impact_unit_SES(prob_impact_unit) global prop_dispatch_SES prob_impact_unit_dis=zeros(3,5); a=prob_impact_unit(3,:)/prop_dispatch_SES; b=prob_impact_unit(2,:)/prop_dispatch_SES; prob_impact_unit_dis(3,:)=prob_impact_unit(3,:)-a; prob_impact_unit_dis(2,:)=prob_impact_unit(2,:)-b; prob_impact_unit_dis(1,:)=prob_impact_unit(1,:)+a+b; if sum(prob_impact_unit_dis)~=100*ones(1,5) disp('prob_impact_init inconsistent') end end %% %*************************************************** % @ pre: state has been generated % @ post: generate an socio-economic status at random % 0 no consideration of SES % 1consideration of SES %*************************************************** function random_SES = generate_SES global disadvantagedSES_rate % probability of being disadvantaged if rand < disadvantagedSES_rate random_SES= 1; else random_SES= 0; end end %% %*********************************************************************** %Technical Utility %*********************************************************************** %% %*************************************************** % @ pre: state has been generated % @ post: compute the number of -1, 0 ,+1 % in the population (state) %*************************************************** function [m1 z0 p1] = get_n(state) global min_age global max_age m1=histc(state(state(:,2)==-1,1),min_age:max_age)'; z0=histc(state(state(:,2)==0,1),min_age:max_age)'; p1=histc(state(state(:,2)==1,1),min_age:max_age)'; end %*********************************************************************** %Empirical data %*********************************************************************** %% %*************************************************** % @ pre: empirical data have been retrieved for years 2001-2004-2008 %http://economie.fgov.be/fr/modules/publications/statistiques/population/ta %bles_de_mortalite.jsp % With columns, defined for men and women: % [px dx Qx] % (px) observed population % (dx) observed death % (Qx) death probability % for ages 65-92 % nb Qx= dx/px % % @ post: empirical data for 2001-2004-2008 are averaged and gathered in % mortalilty data for ages 65-92 %*************************************************** function mortality_data = retreive_mortality pop_stat_2008 = [ %65 90748 1109 0.012221 82481 1110 0.013458 91407 1302 0.014244 98181 1510 0.015380 98903 1661 0.016794 94182 1662 0.017647 90932 1865 0.020510 88889 1938 0.021802 89153 2204 0.024722 87281 2384 0.027314 88592 2696 0.030432 86577 3002 0.034674 84009 3254 0.038734 75611 3269 0.043234 71567 3662 0.051169 66301 3567 0.053800 62861 3913 0.062248 59421 4162 0.070043 54153 4307 0.079534 49297 4363 0.088504 43472 4371 0.100547 38874 4326 0.111283 33416 4205 0.125838 21752 3066 0.140953 12929 2010 0.155464 10612 1759 0.165756 9706 1828 0.188337 9380 1941 0.206930 ]; pop_stat_2004 = [ %65 104671 1338 0.012783 99931 1291 0.012919 97065 1419 0.014619 95695 1556 0.016260 96605 1696 0.017556 95585 1872 0.019585 98060 2154 0.021966 96943 2448 0.025252 95391 2723 0.028546 87183 2621 0.030063 83731 2911 0.034766 79428 3102 0.039054 76840 3305 0.043011 74505 3633 0.048762 69850 3735 0.053472 65774 3983 0.060556 59909 4033 0.067319 56156 4283 0.076270 50789 4320 0.085058 34552 3208 0.092846 21910 2336 0.106618 19001 2268 0.119362 18751 2478 0.132153 19504 2859 0.146585 19432 3101 0.159582 15891 2821 0.177522 12715 2480 0.195045 9522 2122 0.222852 ]; pop_stat_2001 = [ %65 100062 1357 0.013562 101415 1501 0.014801 100851 1660 0.016460 104144 1905 0.018292 103508 2023 0.019544 102331 2308 0.022554 94565 2276 0.024068 91636 2514 0.027435 87761 2546 0.029011 86144 2832 0.032875 84435 3050 0.036122 80628 3344 0.041474 76884 3520 0.045783 71469 3660 0.051211 68549 3872 0.056485 63797 4083 0.064000 44678 3223 0.072138 28971 2269 0.078320 26269 2319 0.088279 26948 2711 0.100601 29156 3235 0.110955 30251 3652 0.120723 26285 3529 0.134259 22274 3468 0.155697 17914 2995 0.167188 14825 2745 0.185160 11457 2249 0.196299 9411 2025 0.215174 ]; u=cat(3,pop_stat_2001,pop_stat_2004,pop_stat_2008); mortality_data=sum(u,3); mortality_data(:,3)= mortality_data(:,2)./mortality_data(:,1); end %% %*************************************************** %@pre : Mortality_data. m retrieve the empirical mortality rate % retrieve %@post: delta_dead has been generated % with the number of number of respondents between % 65 and 92 years old % => at 93 the number of respondent is set to let everybody die) %*************************************************** function delta_dead = die_delta_dead (initial_pop_size) XI=[65:93]' ; YI=compute_artificial_pop(initial_pop_size)'; ZI=[]; %die each year for i =1: size(YI,1)-1 ZI=[ZI; YI(i)-YI(i+1)]; end ZI=[ZI; YI(size(YI,1),1)]; delta_dead=[XI ZI]; end %% %*************************************************** % @ pre: pop_size is the size of the population we want to mimic % @ post: a population size evluation reflecting real (mean) mortality % rate (see retrieve mortality) is returned for ages 65-92 %*************************************************** function artificial_pop= compute_artificial_pop(pop_size) mortality_data = retreive_mortality; [a,b]=size(mortality_data); artificial_pop=[pop_size]; for i=1:a pop_size=pop_size - round(pop_size*mortality_data(i,3)); artificial_pop=[artificial_pop pop_size] ; end end %******************************************************* %drawing %******************************************************* %% %*************************************************** % @ pre: % @ post: the empirical mean prevalence and its CI is % drawn in dashed line from ages 65 to 92 %*************************************************** function draw_empirical_filigrane [A prevallyears nallyears CI_low CI_high]= load_empirical_data; plotall=plot(1:28,A(:,prevallyears),'k--'); %1:28 => 65-92 from 65 set(plotall,'LineWidth',1); hold on plotmin=plot(1:28,A(:,CI_low),'k--'); set(plotmin,'LineWidth',1); plotmax=plot(1:28,A(:,CI_high),'k--'); set(plotmax,'LineWidth',1); end %% %*************************************************** % @ pre: prev_m1 are the prevalence by age gathered through all simulation % prev_m1 is 32 columns (61:92) % and the number of rows is the number of simulations. % @ post: the plot with the simulated data is drawn %*************************************************** function [ploti prev_m1]= draw_one_plot(Sim_curves) prev_m1=mean(Sim_curves(:,5:32),1); %5:32=> 65-92 from 65 on (61(age) = 1(index)) ploti=plot(1:28,prev_m1); set(ploti,'LineWidth',2); BOX OFF xlim([1 29]); set(gca,'FontSize',16,'Xtick',[1:5:29],'XtickLabel',['65';'70';'75';'80';'85';'90';'95']); set(gca,'FontSize',16); ylabel('Prevalence depressison (%)','FontSize',16); xlabel('Age','FontSize',16); end %% %*************************************************** % @ pre: % @ post: draw the regression line %*************************************************** %plot the empirical regression function h= draw_regression; X=regressed_prev; h= plot(X); end %*************************************************** % @ pre: % @ post: Empirical prevalences of depression % retrieved from HIS are saved in matrix A % prevallyears =1st column is the prevalence by year; % nallyears = the 2nd column total number of respondents; % CI_low = the 3rd column is the lower bound of the CI; % CI_high = the 3rd column is the upperd bound of the CI; %*************************************************** function [A prevallyears nallyears CI_low CI_high]= load_empirical_data prevallyears =1; nallyears = 2; CI_low = 3; CI_high = 4; A=[ 8.2 333 3.1 13.2 9.5 335 5.4 13.5 8.7 316 4.7 12.7 10.5 312 5.9 15.0 12.1 315 7.1 17.2 10.9 315 6.2 15.6 18.2 294 6.2 30.1 12.6 311 8.1 17.1 12.7 280 7.7 17.6 16.1 266 9.9 22.2 10.6 264 5.3 15.9 7.9 250 3.8 12.1 8.8 225 4.7 13.0 10.6 210 5.8 15.4 21 195 11.8 30.2 12.5 213 7.1 17.9 15 153 6.6 23.3 13.7 157 6.4 21.0 12.3 133 6.3 18.3 15.9 178 9.6 22.2 20.2 225 12.1 28.3 18.4 205 8.1 28.7 14.7 188 7.7 21.7 17.3 161 9.6 25.0 18.1 107 8.9 27.3 16.3 79 4.2 28.4 11.2 70 0.6 21.8 10.1 54 1.4 18.9 ]; %************************************************* end %******************************************************* % Stat test and numerical test %******************************************************* %% %*************************************************** % @ pre: sim_curve are the last iterations of multiple simulations % representin the simulated prevalence of(by lines) % @ post: The following statistics and information are computed: % - Wilcoxon signed rank test for zero median (P,H) % two-sided test of the hypothesis that the difference between % the matched samples in the vectors X and Y % comes from a distribution whose median is zero % P is the probability of observing the given result, or one more % extreme, by chance if the null hypothesis ("median is zero") is true. % H=0 indicates that the null hypothesis ("median is zero") % cannot be rejected at the 5% level. % H=1 indicates that the null hypothesis can be rejected at the % 5% level. % - ks test with regression line [H,P,KSSTAT] % H = 0 => Do not reject the null hypothesis at significance level 5%. % H = 1 => Reject the null hypothesis at significance level 5%. % P=asymptotic P-value % K-S= test statistic % - correlation coefficient with regression line %*************************************************** function TS = compute_TS(Sim_curves) prev_m1=mean(Sim_curves(:,5:32),1)'; %5:32=> 65-92 from 65 on (61(age) = 1(index)) [A prevallyears nallyears CI_low CI_high]=load_empirical_data; empirical_curve= A(:,prevallyears); % Wilcoxon signed rank test for zero median. %(p-value and H=1 indicates that the null hypothesis can be rejected at the %5% level [P H]=signrank(prev_m1,empirical_curve); %signed_rank TS=[P H]; X=regressed_prev; %ks test with regression line [H,P,KSSTAT]=kstest2(prev_m1,X); TS=[TS [H,P,KSSTAT]]; %correlation coefficient with regression line Rreg=corrcoef(prev_m1,X); TS=[TS Rreg(1,2)]; end %% %*************************************************** % @ pre: sim_curve are the last iterations of multiple simulations % representin the simulated prevalence of(by lines) % @ post: compute the number of occurences of the mean of the % simulated curves falling within the CI bounds (between 65 and 92) %*************************************************** function within_CI = compute_Num_index(Sim_curves) prev_m1=mean(Sim_curves(:,5:32),1)'; %5:32=> 65-92 from 65 on (61(age) = 1(index)) [A prevallyears nallyears CI_low CI_high]=load_empirical_data; %how many time within the interval I=find(prev_m1(:,1)<= A(:,CI_high) & prev_m1(:,1)>=A(:,CI_low)); within_CI=size(I,1); disp('number of occurences within CI') within_CI end %******************************************************* % Regresssion %******************************************************* %% %*************************************************** % @ pre: % @ post: compute the regression line on the empirical % prevalnence %*************************************************** function X=regressed_prev [A prevallyears nallyears CI_low CI_high]= load_empirical_data; [a,b]=size(A); H=regress(A(:,1),[[1:a]' ones(a,1)]); X=(H(1,1)*[1:a]') + H(2,1); end