clc;
clear;
% Main script
% Define the network Activity =
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 ,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51];
Duration =
[5,2,5,2,3,3,6,4,3,4,2,3,3,4,4,1,6,5,10,7,1,11,3,5,5,7,3,3,3,3,2,6,5,2,4,2,2,2,7, 7,5,5,14,5,7,4,1,2,7,5,2];
Predecessors =
{[],1,1,3,2,4,[1,3],7,8,8,10,9,11,5,6,7,7,17,[14,15],[14,15],7,[12,13],[16,17,18]
,19,24,3,26,26,28,27,30,31,[30,31],33,33,35,34,37,30,39,32,41,[39,40],43,[37,38], [41,42],32,[21,37,38],[43,44],49,50};
Relationship =
{{},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS','FS'},{'FS'},{'FS'},{'FS'},{'FS'},{' FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS','FS'},{'FS','FS'},{'FS'},{'F S','FS'},{'FS','FS','FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'}
,{'FS'},{'FS','FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'},{'FS'
},{'FS','FS'},{'FS'},{'FS','FS'},{'FS','FS'},{'FS'},{'FS','FS','FS'},{'FS','FS'}, {'FS'},{'FS'}};
Lag =
{[0],[0],[0],[0],[0],[0],[0,0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0,0], [0,0],[0],[0,0],[0,0,0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0,0],[0],[0],[0],[0]
,[0],[0],[0],[0],[0],[0,0],[0],[0,0],[0,0],[0],[0,0,0],[0,0],[0],[0]};
RiskMoney =
[10,200,200,50,100,50,370,350,400,450,350,300,179,100,100,20,100,200,600,800,80,7 0,50,300,433,100,200,200,150,400,300,40,447,255,437,140,100,100,600,400,200,300,2 71,200,200,50,50,100,200,50,50];
% Calculate ES, EF, LS, LF, and TF
[ES, EF, LS, LF, TF] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag);
% Calculate SOR
SOR = calculateSOR(ES, EF, Duration, Activity);
% Display total initial SOR value disp('Initial SOR:');
disp(SOR);
nvars = length(Activity);
lb = zeros(1, nvars);
% Define MaxTF MaxTF = max(TF);
% Set the upper bound as the minimum of TF and MaxTF ub = min(TF, MaxTF);
intCon = 1:nvars; % Define integer constraints
% Define multi-33 fitness function
fitnessFunctionWrapper = @(x) [objective2(x, ES, EF, Duration, Activity, Predecessors, Relationship, Lag), ...
objective1(x, ES, EF, Duration, Activity, Predecessors, Relationship, Lag, RiskMoney), ...
objective3(x, ES, EF, Duration, Activity, Predecessors, Relationship, Lag)];
% Print the results
T = table(Activity', Duration', ES', EF', LS', LF', TF', RiskMoney', 'VariableNames', {'Activity', 'Duration', 'ES', 'EF', 'LS', 'LF', 'TF', 'RiskMoney'});
disp(T);
% Find the critical path
criticalPath = Activity(TF == 0);
disp("The critical path is:");
disp(criticalPath);
% Calculate project duration totalDuration = max(EF);
disp("The total project duration is:");
disp(totalDuration);
% Set GA options popSize = 500;
maxGenerations = 500;
crossoverFraction = 0.8;
stallGenLimit = 500;
options = optimoptions('gamultiobj', 'PopulationSize', popSize, 'MaxGenerations', maxGenerations, 'StallGenLimit', stallGenLimit, 'Display', 'iter', 'PlotFcn', {@myGaplotPareto},'CrossoverFcn', @myCrossoverFcn);
% Run the GA
[xPareto, fvalPareto] = gamultiobj(fitnessFunctionWrapper, nvars, [], [], [], [], lb, ub, [], intCon, options);
% Display Pareto front results disp('Pareto front results:');
disp([xPareto, fvalPareto]);
% Sort Pareto front solutions based on the total overlap days [sortedFvalPareto, sortedIdx] = sortrows(fvalPareto, 1);
sortedXPareto = xPareto(sortedIdx, :);
% Find the best solution for each objective
[minObjective1, idxObjective1] = min(fvalPareto(:, 1));
[minObjective2, idxObjective2] = min(fvalPareto(:, 2));
[minObjective3, idxObjective3] = min(fvalPareto(:, 3));
% Display the best solutions
disp('Best solution for Objective 1:');
disp(['Total Overlap Days: ', num2str(minObjective1)]);
disp('Movable Duration:');
movable_duration_obj1 = xPareto(idxObjective1, :);
disp(movable_duration_obj1);
disp(xPareto(idxObjective1, :));
disp('Best solution for Objective 2:');
disp(['Total Risk Money: ', num2str(minObjective2)]);
disp('Movable Duration:');
movable_duration_obj2 = xPareto(idxObjective2, :);
disp(movable_duration_obj2);
disp(xPareto(idxObjective2, :));
% Find the best solution for Objective 3
[minObjective3, idxObjective3] = min(fvalPareto(:, 3));
disp('Best solution for Objective 3:');
disp(['Total SOR: ', num2str(minObjective3, '%.4f')]);
disp('Movable Duration:');
movable_duration_obj3 = xPareto(idxObjective3, :);
disp(movable_duration_obj3);
disp(xPareto(idxObjective3, :));
% Calculate new ES, EF, LS, LF, and TF for the best solutions
[ES_obj1, EF_obj1, LS_obj1, LF_obj1, TF_obj1] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag, ES + xPareto(idxObjective1, :));
[ES_obj2, EF_obj2, LS_obj2, LF_obj2, TF_obj2] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag, ES + xPareto(idxObjective2, :));
[ES_obj3, EF_obj3, LS_obj3, LF_obj3, TF_obj3] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag, ES + xPareto(idxObjective3, :));
% Create SOR table for objective 3
SOR_obj3 = calculateSOR(ES_obj3, EF_obj3, Duration, Activity);
% Create new tables for best solutions
T_obj1 = table(Activity', Duration', ES_obj1', EF_obj1', LS_obj1', LF_obj1', TF_obj1', RiskMoney', 'VariableNames', {'Activity', 'Duration', 'ES', 'EF', 'LS', 'LF', 'TF', 'RiskMoney'});
T_obj2 = table(Activity', Duration', ES_obj2', EF_obj2', LS_obj2', LF_obj2', TF_obj2', RiskMoney', 'VariableNames', {'Activity', 'Duration', 'ES', 'EF', 'LS', 'LF', 'TF', 'RiskMoney'});
T_obj3 = table(Activity', Duration', ES_obj3', EF_obj3', LS_obj3', LF_obj3', TF_obj3', RiskMoney', 'VariableNames', {'Activity', 'Duration', 'ES', 'EF', 'LS', 'LF', 'TF', 'RiskMoney'});
% Display the new tables
disp('New table activity for best solution of Objective 1:');
disp(T_obj1);
disp('New table activity for best solution of Objective 2:');
disp(T_obj2);
disp('New table activity for best solution of Objective 3:');
disp(T_obj3);
% Define objective functions
function totalRiskMoney = objective1(x, ES, EF, Duration, Activity, Predecessors, Relationship, Lag, RiskMoney)
% Calculate ES and EF for the given x values ES_opt = ES + x;
[ES_opt, EF_opt, ~, ~, ~] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag, ES_opt);
% Calculate total risk money
OverlapF = zeros(length(Activity));
for i = 1:length(Activity)-1 for j = i+1:length(Activity)
OverlapF(i,j) = max(0, min(EF_opt(i), EF_opt(j)) - max(ES_opt(i), ES_opt(j)));
end end
OverlapRiskMoney = OverlapF .* (RiskMoney' + RiskMoney);
totalRiskMoney = sum(OverlapRiskMoney(:));
end
function totalOverlapDays = objective2(x, ES, EF, Duration, Activity, Predecessors, Relationship, Lag)
% Calculate ES and EF for the given x values ES_opt = ES + x;
[ES_opt, EF_opt, ~, ~, ~] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag, ES_opt);
% Calculate total overlapping days OverlapDays = zeros(length(Activity));
for i = 1:length(Activity)-1 for j = i+1:length(Activity)
OverlapDays(i,j) = max(0, min(EF_opt(i), EF_opt(j)) - max(ES_opt(i), ES_opt(j)));
end end
totalOverlapDays = sum(OverlapDays(:));
end
function totalSOR = objective3(x, ES, EF, Duration, Activity, Predecessors, Relationship, Lag)
% Calculate ES and EF for the given x values ES_opt = ES + x;
[ES_opt, EF_opt, ~, ~, ~] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag, ES_opt);
% Calculate SOR
SOR = calculateSOR(ES_opt, EF_opt, Duration, Activity);
% Calculate total SOR totalSOR = 0;
for i = 1:length(Activity)-1 for j = i+1:length(Activity) totalSOR = sum(sum(SOR));
end end end
function SOR = calculateSOR(ES, EF, Duration, Activity, ~) SOR = zeros(length(Activity));
for i = 1:length(Activity) for j = 1:length(Activity) if i ~= j
% Calculate SOR based on different cases if ES(j) <= ES(i) && EF(j) <= EF(i)
SOR(i,j) = (EF(j) - ES(i))/Duration(j); % Case 1
elseif ES(j) <= ES(i) && EF(j) >= EF(i)
SOR(i,j) = (EF(i) - ES(i))/Duration(j); % Case 2
elseif ES(j) >= ES(i) && EF(j) <= EF(i) SOR(i,j) = 1; % Case 3
elseif ES(j) >= ES(i) && EF(j) >= EF(i)
SOR(i,j) = (EF(i) - ES(j))/Duration(j); % Case 4
elseif ES(j) >= EF(i) || EF(j) <= ES(i) SOR(i,j) = 0; % Case 5
end
% Set negative SOR values to 0 if SOR(i, j) < 0
SOR(i, j) = 0;
end end end end end
function [ES, EF, LS, LF, TF] = calculateProjectTimes(Duration, Activity, Predecessors, Relationship, Lag, ES_initial)
if nargin < 6
ES_initial = [];
end
% Calculate ES and EF n = length(Activity);
ES = zeros(1, n);
EF = zeros(1, n);
if ~isempty(ES_initial)
ES = ES_initial;
end
for i = 1:n
if isempty(ES_initial)
if isempty(Predecessors{i}) ES(i) = 0;
else
tempES = zeros(1, length(Predecessors{i}));
for j = 1:length(Predecessors{i}) pred = Predecessors{i}(j);
relation = Relationship{i}{j};
lag = Lag{i}(j);
if strcmp(relation, 'FS') tempES(j) = EF(pred) + lag;
elseif strcmp(relation, 'FF')
tempES(j) = EF(pred) - Duration(i) + lag;
elseif strcmp(relation, 'SS') tempES(j) = ES(pred) + lag;
elseif strcmp(relation, 'SF') tempEF = EF(pred) + lag;
tempES(j) = tempEF - Duration(i);
end end
ES(i) = max(tempES);
end end
EF(i) = ES(i) + Duration(i);
end
% Calculate LF and LS LF = zeros(size(Activity));
LS = zeros(size(Activity));
LF(end) = EF(end);
LS(end) = ES(end);
for i = length(Activity)-1:-1:1
successors = find(cellfun(@(x) ismember(i, x), Predecessors));
if isempty(successors) LF(i) = EF(end);
else
tempLF = ones(1, length(successors)) * inf;
for k = 1:length(successors) suc = successors(k);
for j = 1:length(Predecessors{suc}) if Predecessors{suc}(j) == i rel = Relationship{suc}{j};
lag = Lag{suc}(j);
switch rel case 'FS'
tempLF(k) = min(tempLF(k), LS(suc) - lag);
case 'FF'
tempLF(k) = min(tempLF(k), LF(suc) - lag);
case 'SS'
tempLF(k) = min(tempLF(k), LS(suc) + Duration(i) - lag);
case 'SF'
tempLF(k) = min(tempLF(k), LF(suc) + Duration(i) - lag);
otherwise
error('Invalid relationship type.');
end end end end
LF(i) = min(tempLF);
end
LS(i) = LF(i) - Duration(i);
end
% Calculate TF TF = LS - ES;
end
function [xoverKids] = myCrossoverFcn(parents, options, nvars, FitnessFcn, unused,thisPopulation)
%MYCROSSOVERFCN Custom crossover function that implements multi-point crossover
% [xoverKids] = MYCROSSOVERFCN(PARENTS, OPTIONS, NVARS, FITNESSFCN, UNUSED, THISPOPULATION)
% Determine crossover points numCrossoverPoints = 2;
crossoverPoints = randi([1 nvars],1,numCrossoverPoints);
% Create offspring solutions by swapping gene values between parents at crossover points
nKids = length(parents)/2;
xoverKids = zeros(nKids,nvars);
index = 1;
for i=1:nKids
parent1 = thisPopulation(parents(index),:);
parent2 = thisPopulation(parents(index+1),:);
for j=1:numCrossoverPoints
xoverKids(i,crossoverPoints(j):end) = parent2(crossoverPoints(j):end);
xoverKids(i,crossoverPoints(j):end) = parent1(crossoverPoints(j):end);
end
index = index + 2;
end end