function [phoneSchedule, phoneTaskCounts, phoneValueCounts] = genUniqueSetups() uniqueSetups = 20; weeks = 50; seasons = 3; months = 12; maxRearrange = 1000; targetGini = 0.01; Time0 = 0; Time1 = 1; Time2 = 2; Time3 = 3; User2 = 2; Time1Interval = 16; Time2Interval = 4; Time3Interval = 1; Time0Repeats = 1; Time1Repeats = 3; Time2Repeats = 12; Time3Repeats = 48; formList = dataset('XLSFile','formSummary.xls'); %in form list, for 'Times: %0: Ask once only at beginning of pilot %1: Ask once per season (3 times per year) %3: Three different versions: per season, per month, per week %in form list, for 'Users: %1: Ask only to user %2: Ask to user, and then ask separately to a friend or neighbor, with same %recall period %Time 0 forms asked 1 time, Time 1 forms asked 3 times, Time 2 forms asked 12 times, and %Time 3 forms asked 48 times. User 2 forms asked 2 times as much %Randomly assign versioning of each form to phones uniquePhones = zeros(uniqueSetups,length(formList),2); uniquePhones(:,formList.Times == 1,1) = 1; uniquePhones(:,formList.Times == Time3,1) = ceil(rand(uniqueSetups,sum(formList.Times == Time3))*Time3); uniquePhones(:,formList.Users == 1,2) = 1; uniquePhones(:,formList.Users == User2,2) = ceil(rand(uniqueSetups,sum(formList.Users == User2))*User2); %calculate the total value in each phone by multiplying the number of times %a task is done through its value and summing timeCount = [Time0Repeats Time1Repeats Time2Repeats Time3Repeats]; phoneValue = sum(timeCount(uniquePhones(:,:,1)+1) .* (ones(uniqueSetups,1)*(formList.Value')) .* uniquePhones(:,:,2),2); giniPhone = calcGini(phoneValue); count = 1; %now do a strategic re-arrange, to try to even out value. Do random %pair-wise substitutions until the GINI for phone value is below tolerance tempValue = 1:length(formList); indexChangeForms = tempValue(formList.Times > 1); while(count < maxRearrange & giniPhone > targetGini) newUniquePhones = uniquePhones; randForm = indexChangeForms(ceil(rand()*length(indexChangeForms))); %choosing only from forms that have different versions across phones randPhones = randperm(uniqueSetups); randPhones = randPhones(1:2); tempValue = newUniquePhones(randPhones(1),randForm,:); newUniquePhones(randPhones(1),randForm,:) = newUniquePhones(randPhones(2),randForm,:); newUniquePhones(randPhones(2),randForm,:) = tempValue; newPhoneValue = sum(timeCount(newUniquePhones(:,:,1)+1) .* (ones(uniqueSetups,1)*(formList.Value')) .* newUniquePhones(:,:,2),2); newGiniPhone = calcGini(newPhoneValue); if(newGiniPhone < giniPhone) giniPhone = newGiniPhone; uniquePhones = newUniquePhones; end count = count + 1; end %now spread the tasks out across the weeks of the pilot %Time 0 forms are asked once the first 2 weeks %Time 1 forms are asked once within each 16 week period following the first %2 weeks %Time 2 forms are asked once within each 4 week period following the first %2 weeks %Time 3 forms are asked once within each week period after the first 2 %weeks phoneSchedule = cell(uniqueSetups,weeks); phoneTaskCounts = zeros(uniqueSetups,weeks); phoneValueCounts = zeros(uniqueSetups,weeks); for indexI = 1:uniqueSetups for indexJ = 1:length(formList) switch uniquePhones(indexI,indexJ,1) case 0 phoneWeek = find(phoneTaskCounts(indexI,1:2) == min(phoneTaskCounts(indexI,1:2))); phoneWeek = phoneWeek(randperm(length(phoneWeek))); phoneWeek = phoneWeek(1); phoneSchedule{indexI,phoneWeek}{end+1} = ['Initial - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); case 1 if uniquePhones(indexI,indexJ,2) == 1 for indexK = 1:seasons phoneWeek = find(phoneTaskCounts(indexI,(indexK-1)*16+3:(indexK)*Time1Interval+2) == min(phoneTaskCounts(indexI,(indexK-1)*Time1Interval+3:(indexK)*Time1Interval+2))); phoneWeek = phoneWeek(randperm(length(phoneWeek))) + (indexK-1)*Time1Interval+2; phoneWeek = phoneWeek(1); phoneSchedule{indexI,phoneWeek}{end+1} = ['Seasonally - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end else for indexK = 1:seasons phoneWeek = find(phoneTaskCounts(indexI,(indexK-1)*Time1Interval+3:(indexK)*Time1Interval+2) == min(phoneTaskCounts(indexI,(indexK-1)*Time1Interval+3:(indexK)*Time1Interval+2))); phoneWeek = phoneWeek(randperm(length(phoneWeek))) + (indexK-1)*Time1Interval+2; phoneWeek = phoneWeek(1); phoneSchedule{indexI,phoneWeek}{end+1} = ['Seasonally - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end for indexK = 1:seasons phoneWeek = find(phoneTaskCounts(indexI,(indexK-1)*Time1Interval+3:(indexK)*Time1Interval+2) == min(phoneTaskCounts(indexI,(indexK-1)*Time1Interval+3:(indexK)*Time1Interval+2))); phoneWeek = phoneWeek(randperm(length(phoneWeek))) + (indexK-1)*Time1Interval+2; phoneWeek = phoneWeek(1); phoneSchedule{indexI,phoneWeek}{end+1} = ['Seasonally_Neighbor - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end end case 2 if uniquePhones(indexI,indexJ,2) == 1 for indexK = 1:months phoneWeek = find(phoneTaskCounts(indexI,(indexK-1)*Time2Interval+3:(indexK)*Time2Interval+2) == min(phoneTaskCounts(indexI,(indexK-1)*Time2Interval+3:(indexK)*Time2Interval+2))); phoneWeek = phoneWeek(randperm(length(phoneWeek))) + (indexK-1)*Time2Interval+2; phoneWeek = phoneWeek(1); phoneSchedule{indexI,phoneWeek}{end+1} = ['Monthly - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end else for indexK = 1:months phoneWeek = find(phoneTaskCounts(indexI,(indexK-1)*Time2Interval+3:(indexK)*Time2Interval+2) == min(phoneTaskCounts(indexI,(indexK-1)*Time2Interval+3:(indexK)*Time2Interval+2))); phoneWeek = phoneWeek(randperm(length(phoneWeek))) + (indexK-1)*Time2Interval+2; phoneWeek = phoneWeek(1); phoneSchedule{indexI,phoneWeek}{end+1} = ['Monthly - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end for indexK = 1:months phoneWeek = find(phoneTaskCounts(indexI,(indexK-1)*Time2Interval+3:(indexK)*Time2Interval+2) == min(phoneTaskCounts(indexI,(indexK-1)*Time2Interval+3:(indexK)*Time2Interval+2))); phoneWeek = phoneWeek(randperm(length(phoneWeek))) + (indexK-1)*Time2Interval+2; phoneWeek = phoneWeek(1); phoneSchedule{indexI,phoneWeek}{end+1} = ['Monthly_Neighbor - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end end case 3 if uniquePhones(indexI,indexJ,2) == 1 for indexK = 1:(weeks - 2) phoneWeek = indexK + 2; phoneSchedule{indexI,phoneWeek}{end+1} = ['Weekly - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end else for indexK = 1:(weeks - 2) phoneWeek = indexK + 2; phoneSchedule{indexI,phoneWeek}{end+1} = ['Weekly - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end for indexK = 1:(weeks - 2) phoneWeek = indexK + 2; phoneSchedule{indexI,phoneWeek}{end+1} = ['Weekly_Neighbor - ' formList.Title{indexJ}]; phoneTaskCounts(indexI,phoneWeek) = phoneTaskCounts(indexI,phoneWeek) + 1; phoneValueCounts(indexI,phoneWeek) = phoneValueCounts(indexI,phoneWeek) + formList.Value(indexJ); end end end end end %output schedules phoneScheduleSheets = cell(uniqueSetups,1); for indexI = 1:uniqueSetups width = 2; for indexJ = 1:weeks tempSheet = cell(7,width); tempSheet(:,1) = {['Week ' num2str(indexJ)]}; tempData = phoneSchedule{indexI, indexJ}; column = 2; while (~isempty(tempData)) currentWeek = tempData(1:min(length(tempData),7)); reorderedWeek = cell(7,1); reorderedWeek(randperm(7,length(currentWeek))) = currentWeek; tempData(1:min(length(tempData),7)) = []; tempSheet(:,column) = reorderedWeek'; if(column > width) width = column; phoneScheduleSheets{indexI} = [phoneScheduleSheets{indexI} cell(size(phoneScheduleSheets{indexI},1),width - size(phoneScheduleSheets{indexI},2))]; end column = column+1; end phoneScheduleSheets{indexI} = [phoneScheduleSheets{indexI}; tempSheet]; end end for indexI = 1:uniqueSetups cell2csv(phoneScheduleSheets{indexI},['phoneSetup' num2str(indexI)]); end end function gini = calcGini(values) n = length(values); index = 1:n; sortValues = sort(values); sumV = sum(values); try sumIV = sum(sortValues.*index); catch sumIV = sum(sortValues'.*index); end gini = 2*sumIV/(n*sumV) - (n+1)/n; end