├── octave-workspace ├── demo.m ├── gaussian_mutate.m ├── test_a.m ├── eval_update.m ├── evaluate.m ├── randompoint.m ├── README.md ├── get_structure.m ├── realmutate.m ├── init_weights.m ├── testmop.m ├── subobjective.m ├── genetic_op.m └── moead.m /octave-workspace: -------------------------------------------------------------------------------- 1 | Octave-1-L -------------------------------------------------------------------------------- /demo.m: -------------------------------------------------------------------------------- 1 | function demo() 2 | % 导入多目标的测试函数 3 | mop = testmop('zdt1', 30); 4 | % 使用moead函数求解多目标最优解 5 | % 种群规模,100,迭代次数,200,相邻种群数,20,方法,te 6 | pareto = moead(mop, 'popsize', 100, 'niche', 20, 'iteration', 200, 'method', 'te'); 7 | 8 | %pareto = moead( mop,'popsize', 100, 'niche', 20, 'iteration', 200, 'method', 'ws'); 9 | 10 | end 11 | -------------------------------------------------------------------------------- /gaussian_mutate.m: -------------------------------------------------------------------------------- 1 | function ind = gaussian_mutate( ind, prob, domain) 2 | %GAUSSIAN_MUTATE Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | if isstruct(ind) 6 | x = ind.parameter; 7 | else 8 | x = ind; 9 | end 10 | 11 | parDim = length(x); 12 | lowend = domain(:,1); 13 | highend =domain(:,2); 14 | sigma = (highend-lowend)./20; 15 | 16 | newparam = min(max(normrnd(x, sigma), lowend), highend); 17 | C = rand(parDim, 1) yu) 42 | y = yu; 43 | end 44 | a(j) = y; 45 | end 46 | end 47 | if isstruct(ind) 48 | ind.parameter = a; 49 | else 50 | ind = a; 51 | end 52 | end 53 | 54 | -------------------------------------------------------------------------------- /init_weights.m: -------------------------------------------------------------------------------- 1 | function subp = init_weights(popsize, niche, objDim) 2 | % 权值向量初始化函数,使用分解权重和近邻关系来初始化权值向量 3 | % init_weights function initialize a pupulation of subproblems structure 4 | % with the generated decomposition weight and the neighbourhood 5 | % relationship. 6 | 7 | % 初始化权值向量 8 | subp = []; 9 | 10 | % 循环所有的种群规模 11 | 12 | for i = 0:popsize 13 | 14 | % 如果目标有两个,这里可以扩展 15 | 16 | if objDim == 2 17 | % 每个子问题都有 18 | p = struct('weight', [], 'neighbour', [], 'optimal', Inf, 'optpoint', [], 'curpoint', []); 19 | 20 | % 平均划分,定义每个权值向量,然后吧定义好的所有向量装进subp 21 | weight = zeros(2, 1); 22 | weight(1) = i / popsize; 23 | weight(2) = (popsize - i) / popsize; 24 | p.weight = weight; 25 | subp = [subp p]; 26 | elseif objDim == 3 27 | %TODO 28 | end 29 | 30 | end 31 | 32 | % weight = lhsdesign(popsize, objDim,'criterion', 'maximin', 'iterations', 1000)'; 33 | % p=struct('weight', [], 'neighbour', [], 'optimal', Inf, 'optpoint', [], 'curpoint', []); 34 | % subp = repmat(p, popsize, 1); 35 | % cells = num2cell(weight); 36 | % [subp.weight]=cells{:}; 37 | 38 | %Set up the neighbourhood. 39 | % 定义邻居 40 | % 每一个向量将邻居中所有的向量中较近的定义为邻居向量。 41 | leng = length(subp); 42 | distanceMatrix = zeros(leng, leng); % 距离矩阵 43 | 44 | % 计算每两个点间的距离 45 | for i = 1:leng 46 | for j = i + 1:leng 47 | 48 | A = subp(i).weight; B = subp(j).weight; 49 | distanceMatrix(i, j) = (A - B)' * (A - B); 50 | distanceMatrix(j, i) = distanceMatrix(i, j); 51 | end 52 | 53 | [s, sindex] = sort(distanceMatrix(i, :)); 54 | subp(i).neighbour = sindex(1:niche)'; 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /testmop.m: -------------------------------------------------------------------------------- 1 | function mop = testmop(testname, dimension) 2 | % 通过输入的名称得到一个多目标的问题 3 | % 这里测试使用的是一个多目标的测试问题或者一个基准的问题 4 | % 我们的问题里面有ZDT问题,OKA问题,KNO问题 5 | % 使用者可以通过传入不同的参数来讨论这些问题 6 | % Get test multi-objective problems from a given name. 7 | % The method get testing or benchmark problems for Multi-Objective 8 | % Optimization. The implemented problems included ZDT, OKA, KNO. 9 | % User get the corresponding test problem, which is an instance of class 10 | % mop, by passing the problem name and optional dimension parameters. 11 | 12 | % 建立一个结构体 13 | mop = struct('name', [], 'od', [], 'pd', [], 'domain', [], 'func', []); 14 | 15 | switch lower(testname) 16 | case 'kno1' 17 | mop = kno1(mop); 18 | case 'zdt1' 19 | mop = zdt1(mop, dimension); 20 | otherwise 21 | error('Undefined test problem name'); 22 | end 23 | 24 | end 25 | 26 | %KNO1 function generator 27 | % KNO1 问题的生成器 28 | 29 | function p = kno1(p) 30 | p.name = 'KNO1'; % 名字 31 | p.od = 2; % 目标的维度 32 | p.pd = 2; % 参数的维度 33 | p.domain = [0 3; 0 3]; % 定义域 34 | p.func = @evaluate; % 评价函数 35 | 36 | % KNO1 evaluation function. 37 | % 定义评价函数 38 | function y = evaluate(x) 39 | y = zeros(2, 1); 40 | c = x(1) + x(2); 41 | f = 9 - (3 * sin(2.5 * c^0.5) + 3 * sin(4 * c) + 5 * sin(2 * c + 2)); 42 | g = (pi / 2.0) * (x(1) - x(2) + 3.0) / 6.0; 43 | y(1) = 20 - (f * cos(g)); 44 | y(2) = 20 - (f * sin(g)); 45 | end 46 | end 47 | 48 | %ZDT1 function generator 49 | 50 | function p = zdt1(p, dim) 51 | p.name = 'ZDT1'; 52 | p.pd = dim; 53 | p.od = 2; 54 | p.domain = [zeros(dim, 1) ones(dim, 1)]; 55 | p.func = @evaluate; 56 | 57 | % KNO1 evaluation function. 58 | 59 | function y = evaluate(x) 60 | y = zeros(2, 1); 61 | y(1) = x(1); 62 | su = sum(x) - x(1); 63 | g = 1 + 9 * su / (dim - 1); 64 | y(2) = g * (1 - sqrt(x(1) / g)); 65 | end 66 | 67 | end 68 | -------------------------------------------------------------------------------- /subobjective.m: -------------------------------------------------------------------------------- 1 | function obj = subobjective(weight, ind, idealpoint, method) 2 | %SUBOBJECTIVE function evaluate a point's objective with a given method of 3 | %decomposition. 4 | 5 | % Two method are implemented by far is Weighted-Sum and Tchebesheff. 6 | % weight: is the decomposition weight.(column wise vector). 7 | % ind: is the individual point(column wise vector). 8 | % idealpoint: the idealpoint for Tchebesheff decomposition. 9 | % method: is the decomposition method, the default is 'te' when is 10 | % omitted. 11 | % 12 | % weight and ind can also be matrix. in which have two scenairos: 13 | % When weight is a matrix, then it's treated as a column wise set of 14 | % weights. in that case, if ind is a size 1 column vector, then the 15 | % subobjective is computed with every weight and the ind; if ind is also 16 | % a matrix of the same size as weight, then the subobjective is computed 17 | % in a column-to-column, with each column of weight computed against the 18 | % corresponding column of ind. 19 | % A row vector of subobjective is return in both case. 20 | 21 | if (nargin==2) 22 | obj = ws(weight, ind); 23 | elseif (nargin==3) 24 | obj = te(weight, ind, idealpoint); 25 | else 26 | if strcmp(method, 'ws') 27 | obj=ws(weight, ind); 28 | elseif strcmp(method, 'te') 29 | obj=te(weight, ind, idealpoint); 30 | else 31 | obj= te(weight, ind, idealpoint); 32 | end 33 | end 34 | end 35 | 36 | function obj = ws(weight, ind) 37 | if size(ind, 2) == 1 38 | obj = (weight'*ind)'; 39 | else 40 | obj = sum(weight.*ind); 41 | end 42 | end 43 | 44 | function obj = te(weight, ind, idealpoint) 45 | s = size(weight, 2); 46 | indsize = size(ind,2); 47 | 48 | weight((weight == 0))=0.00001; 49 | 50 | if indsize==s 51 | part2 = abs(ind-idealpoint(:,ones(1, indsize))); 52 | obj = max(weight.*part2); 53 | elseif indsize ==1 54 | part2 = abs(ind-idealpoint); 55 | obj = max(weight.*part2(:,ones(1, s))); 56 | else 57 | error('individual size must be same as weight size, or equals 1'); 58 | end 59 | end -------------------------------------------------------------------------------- /genetic_op.m: -------------------------------------------------------------------------------- 1 | function ind = genetic_op(subproblems, index, domain, params) 2 | % 使用当前的种群进行差分进化 3 | %GENETICOP function implemented the DE operation to generate a new 4 | %individual from a subproblems and its neighbours. 5 | 6 | % subproblems: is all the subproblems. 所有的子问题 7 | % index: the index of the subproblem need to handle. 子问题的编号 8 | % domain: the domain of the origional multiobjective problem. 定义域 9 | % ind: is an individual structure. 个人结构? 10 | 11 | % 提取出邻居矩阵 12 | neighbourindex = subproblems(index).neighbour; 13 | 14 | %The random draw from the neighbours. 15 | % 从邻居中进行随机的抽取 16 | nsize = length(neighbourindex); 17 | si = ones(1, 3) * index; 18 | 19 | si(1) = neighbourindex(ceil(rand * nsize)); 20 | 21 | while si(1) == index 22 | si(1) = neighbourindex(ceil(rand * nsize)); 23 | end 24 | 25 | si(2) = neighbourindex(ceil(rand * nsize)); 26 | 27 | while si(2) == index || si(2) == si(1) 28 | si(2) = neighbourindex(ceil(rand * nsize)); 29 | end 30 | 31 | si(3) = neighbourindex(ceil(rand * nsize)); 32 | 33 | while si(3) == index || si(3) == si(2) || si(3) == si(1) 34 | si(3) = neighbourindex(ceil(rand * nsize)); 35 | end 36 | 37 | %retrieve the individuals. 38 | points = [subproblems(si).curpoint]; 39 | selectpoints = [points.parameter]; 40 | 41 | oldpoint = subproblems(index).curpoint.parameter; 42 | parDim = size(domain, 1); 43 | 44 | jrandom = ceil(rand * parDim); 45 | 46 | randomarray = rand(parDim, 1); 47 | deselect = randomarray < params.CR; 48 | deselect(jrandom) = true; 49 | newpoint = selectpoints(:, 1) + params.F * (selectpoints(:, 2) - selectpoints(:, 3)); 50 | newpoint(~deselect) = oldpoint(~deselect); 51 | 52 | %repair the new value. 53 | newpoint = max(newpoint, domain(:, 1)); 54 | newpoint = min(newpoint, domain(:, 2)); 55 | 56 | ind = struct('parameter', newpoint, 'objective', [], 'estimation', []); 57 | %ind.parameter = newpoint; 58 | %ind = realmutate(ind, domain, 1/parDim); 59 | ind = gaussian_mutate(ind, 1 / parDim, domain); 60 | 61 | %clear points selectpoints oldpoint randomarray deselect newpoint neighbourindex si; 62 | end 63 | -------------------------------------------------------------------------------- /moead.m: -------------------------------------------------------------------------------- 1 | function pareto = moead(mop, varargin) 2 | 3 | %MOEAD runs moea/d algorithms for the given mop. 4 | % Detailed explanation goes here 5 | % The mop must to be minimizing. 6 | % The parameters of the algorithms can be set through varargin. including 7 | % popsize: The subproblem's size. 8 | % niche: the neighboursize, must less then the popsize. 9 | % iteration: the total iteration of the moead algorithms before finish. 10 | % method: the decomposition method, the value can be 'ws' or 'ts'. 11 | 12 | % 定义开始时间 13 | starttime = clock; 14 | % global variable definition. 15 | % 定义全局变量 16 | global params idealpoint objDim parDim itrCounter; 17 | % set the random generator. 18 | % 定义随机生成器 19 | rand('state', 10); 20 | 21 | %Set the algorithms parameters. 22 | % 定义算法的参数,将输入的参数通过init函数导入 23 | paramIn = varargin; 24 | [objDim, parDim, idealpoint, params, subproblems] = init(mop, paramIn); 25 | 26 | % 初始化循环编号 27 | itrCounter = 1; 28 | 29 | % 主循环 30 | while ~terminate(itrCounter) 31 | tic; 32 | subproblems = evolve(subproblems, mop, params); 33 | disp(sprintf('iteration %u finished, time used: %u', itrCounter, toc)); 34 | itrCounter = itrCounter + 1; 35 | end 36 | 37 | %display the result. 38 | pareto = [subproblems.curpoint]; 39 | pp = [pareto.objective]; 40 | scatter(pp(1, :), pp(2, :)); 41 | disp(sprintf('total time used %u', etime(clock, starttime))); 42 | end 43 | 44 | function [objDim, parDim, idealp, params, subproblems] = init(mop, propertyArgIn) 45 | %Set up the initial setting for the MOEA/D. 46 | objDim = mop.od; % 获取目标的维度 47 | parDim = mop.pd; % 获取参数的维度 48 | idealp = ones(objDim, 1) * inf; % ? 49 | 50 | %the default values for the parameters. 51 | % 其他参数的默认值 52 | params.popsize = 100; params.niche = 30; params.iteration = 100; 53 | params.dmethod = 'ts'; 54 | params.F = 0.5; 55 | params.CR = 0.5; 56 | 57 | % handle the parameters, mainly about the popsize 58 | % 处理输入的参数 59 | while length(propertyArgIn) >= 2 60 | prop = propertyArgIn{1}; 61 | val = propertyArgIn{2}; 62 | propertyArgIn = propertyArgIn(3:end); 63 | 64 | switch prop 65 | case 'popsize' 66 | % 种群规模 67 | params.popsize = val; 68 | case 'niche' 69 | %相邻种群规模 70 | params.niche = val; 71 | case 'iteration' 72 | % 迭代次数 73 | params.iteration = val; 74 | case 'method' 75 | % 方法 76 | params.dmethod = val; 77 | otherwise 78 | warning('moea doesnot support the given parameters name'); 79 | end 80 | 81 | end 82 | 83 | % 初始化权向量,将问题分解成多个单目标问题 84 | subproblems = init_weights(params.popsize, params.niche, objDim); 85 | params.popsize = length(subproblems); % 这一句好像是多余的,把100变成了101 86 | 87 | %initial the subproblem's initital state. 88 | % 初始化初始点 89 | inds = randompoint(mop, params.popsize); 90 | 91 | % 对初始化的点进行评价,并且吧最优点保存在idealp中。 92 | [V, INDS] = arrayfun(@evaluate, repmat(mop, size(inds)), inds, 'UniformOutput', 0); 93 | v = cell2mat(V); 94 | idealp = min(idealp, min(v, [], 2)); 95 | 96 | %indcells = mat2cell(INDS, 1, ones(1,params.popsize)); 97 | [subproblems.curpoint] = INDS{:}; 98 | clear inds INDS V indcells; 99 | end 100 | 101 | function subproblems = evolve(subproblems, mop, params) 102 | global idealpoint; 103 | 104 | for i = 1:length(subproblems) 105 | %new point generation using genetic operations, and evaluate it. 106 | ind = genetic_op(subproblems, i, mop.domain, params); 107 | [obj, ind] = evaluate(mop, ind); 108 | %update the idealpoint. 109 | idealpoint = min(idealpoint, obj); 110 | 111 | %update the neighbours. 112 | neighbourindex = subproblems(i).neighbour; 113 | subproblems(neighbourindex) = update(subproblems(neighbourindex), ind, idealpoint); 114 | %clear ind obj neighbourindex neighbours; 115 | 116 | clear ind obj neighbourindex; 117 | end 118 | 119 | end 120 | 121 | function subp = update(subp, ind, idealpoint) 122 | global params 123 | 124 | newobj = subobjective([subp.weight], ind.objective, idealpoint, params.dmethod); 125 | oops = [subp.curpoint]; 126 | oldobj = subobjective([subp.weight], [oops.objective], idealpoint, params.dmethod); 127 | 128 | C = newobj < oldobj; 129 | [subp(C).curpoint] = deal(ind); 130 | clear C newobj oops oldobj; 131 | end 132 | 133 | function y = terminate(itrcounter) 134 | global params; 135 | y = itrcounter > params.iteration; 136 | end 137 | --------------------------------------------------------------------------------