Skip to content

Commit 5cb41d7

Browse files
committed
updates and streamlining to core code
1 parent 0c47d6c commit 5cb41d7

19 files changed

+711
-208
lines changed

Contents.m

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
% FFDSAIL
2+
%
3+
% Files
4+
% runSail - - Example usage script of sail function

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ https://hal.inria.fr/hal-01518786/file/aiaa_sail.pdf
1919
public as their are published. If you are interested in creating a new
2020
domain and having trouble, don't hesistate to ask!
2121

22+
A third domain is now included airfoils created with free form deformations.
23+
2224
Produced using
2325
Matlab Version: 9.1.0.441655 (R2016b)
2426

addAllToPath.m

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
%addAllToPath - This function adds all folders above it to the path
2+
%
3+
% Author: Adam Gaier
4+
% Bonn-Rhein-Sieg University of Applied Sciences (HBRS)
5+
% email: adam.gaier@h-brs.de
6+
% Oct 2017; Last revision: 09-Oct-2017
7+
8+
%------------- BEGIN CODE --------------
9+
% Clean up workspace and add relevant files to path
10+
currentPath = mfilename('fullpath');
11+
addpath(genpath(currentPath(1:end-length(mfilename))));
12+
addpath(genpath('~/Code/matlabExtensions/'));
13+
14+

mapElites/createChildren.m

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
function children = createChildren(map, p, d)
1+
function children = createChildren(map, nChildren, p, d)
22
%createChildren - produce new children through mutation of map elite
33
%
4-
% Syntax: children = createChildren(map,p)
4+
% Syntax: children = createChildren(map,nChildren,p,d)
55
%
66
% Inputs:
7-
% map - Population struct
7+
% map - Population struct
88
% .fitness
99
% .genes
10-
% .<additional info> (e.g., drag, lift, etc)
11-
% p - SAIL hyperparameter struct
12-
% .nChildren - number of children created
13-
% .mutSigma - sigma of gaussian mutation applied to children
14-
% d - Domain description struct
15-
% .dof - Degrees of freedom (genome length)
10+
% nChildren - number of children to create
11+
% p - SAIL hyperparameter struct
12+
% .mutSigma - sigma of gaussian mutation applied to children
13+
% d - Domain description struct
14+
% .dof - Degrees of freedom (genome length)
1615
%
1716
% Outputs:
1817
% children - [nChildren X genomeLength] - new solutions
@@ -22,16 +21,16 @@
2221
% Author: Adam Gaier
2322
% Bonn-Rhein-Sieg University of Applied Sciences (HBRS)
2423
% email: adam.gaier@h-brs.de
25-
% Jun 2016; Last revision: 01-Aug-2017
24+
% Jun 2016; Last revision: 17-Oct-2017
2625

2726
%------------- BEGIN CODE --------------
2827
% Remove empty bins from parent pool
2928
parentPool = reshape(map.genes,[numel(map.fitness), d.dof]);
3029
parentPool(isnan(parentPool(:,1)),:) = [];
3130

3231
% Choose parents and create mutation
33-
parents = parentPool(randi([1 size(parentPool,1)], [p.nChildren 1]), :);
34-
mutation = randn(p.nChildren,d.dof) .* p.mutSigma;
32+
parents = parentPool(randi([1 size(parentPool,1)], [nChildren 1]), :);
33+
mutation = randn(nChildren,d.dof) .* p.mutSigma;
3534

3635
% Apply mutation
3736
children = parents + mutation;

mapElites/mapElites.m

+32-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function [map, h] = mapElites(fitnessFunction,map,p,d)
1+
function [map, percImproved, h] = mapElites(fitnessFunction,map,p,d)
22
%mapElites - Multi-dimensional Archive of Phenotypic Elites algorithm
33
%
44
% Syntax: map = mapElites(fitnessFunction, map, p, d);
@@ -11,6 +11,7 @@
1111
%
1212
% Outputs:
1313
% map - struct - population archive
14+
% percImproved - percentage of children which improved on elites
1415
% h - [1X2] - axes handle, data handle
1516
%
1617
%
@@ -19,47 +20,53 @@
1920
% Author: Adam Gaier
2021
% Bonn-Rhein-Sieg University of Applied Sciences (HBRS)
2122
% email: adam.gaier@h-brs.de
22-
% Jun 2016; Last revision: 02-Aug-2017
23+
% Jun 2016; Last revision: 17-Oct-2017
2324

24-
%------------- BEGIN CODE --------------
25+
% TODO:
26+
% parser instead of the sloppy ifs at top
2527

28+
%------------- BEGIN CODE --------------
2629
% View Initial Map
2730
h = [];
2831
if p.display.illu
2932
figure(2); clf;
3033
[h(1), h(2)] = viewMap(map.fitness, d, map.edges); title('Illumination Fitness')
3134
end
3235

33-
iGen = 0;
34-
while (iGen < p.nGens)
35-
%% Create and Evaluate Children
36-
% Continue to remutate until enough children which satisfy geometric
37-
% constraints are created
38-
children = [];
39-
while size(children,1) < p.nChildren
40-
newChildren = createChildren(map, p, d);
41-
validInds = feval(d.validate,newChildren,d);
42-
children = [children ; newChildren(validInds,:)] ; %#ok<AGROW>
43-
end
44-
children = children(1:p.nChildren,:);
45-
[fitness, values] = fitnessFunction(children); %% TODO: Speed up without anonymous functions
36+
%% MAP-Elites
37+
iGen = 1;
38+
while (iGen <= p.nGens)
39+
%% 1) Create and Evaluate Children
40+
% Create children which satisfy geometric constraints for validity
41+
nMissing = p.nChildren; children = [];
4642

47-
%% Add Children to Map
48-
[replaced, replacement] = nicheCompete(children,fitness,map,d);
43+
while nMissing > 0
44+
indPool = createChildren(map, nMissing, p, d);
45+
validFunction = @(genomes) feval(d.validate, genomes, d);
46+
[validChildren,~,nMissing] = getValidInds(indPool, validFunction, nMissing);
47+
children = [children; validChildren]; %#ok<AGROW>
48+
end
49+
50+
[fitness, values] = fitnessFunction(children); %% TODO: Speed up without anonymous functions
51+
52+
%% 2) Add Children to Map
53+
[replaced, replacement] = nicheCompete(children,fitness,map,d);
4954
map = updateMap(replaced,replacement,map,fitness,children,...
5055
values,d.extraMapValues);
51-
52-
%% View New Map
56+
57+
% Improvement Stats
58+
percImproved(iGen) = length(replaced)./p.nChildren; %#ok<AGROW>
59+
60+
% View Illuminatiom Progress?
5361
if p.display.illu && ~mod(iGen,p.display.illuMod)
54-
set(h(2),'CData',flip(map.fitness),...
55-
'AlphaData',~isnan(flip(map.fitness)))
56-
colormap(h(1),parula(16));
57-
drawnow;
62+
set(h(2),'CData',flip(map.fitness),'AlphaData',~isnan(flip(map.fitness)))
63+
colormap(h(1),parula(16)); drawnow;
5864
end
5965

60-
iGen = iGen+1; if ~mod(iGen,100);disp([char(9) 'Illumination Generation: ' int2str(iGen)]);end;
66+
iGen = iGen+1; if ~mod(iGen,2^5);disp([char(9) 'Illumination Generation: ' int2str(iGen) ' - Improved: ' num2str(percImproved(end)*100) '%']);end;
6167
end
6268

69+
if percImproved(end) > 0.05; disp('Warning: MAP-Elites finished while still making improvements ( >5% / generation )');end
6370

6471

6572
%------------- END OF CODE --------------

mapElites/nicheCompete.m

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function [replaced, replacement] = nicheCompete(newInds,fitness,map,d)
1+
function [replaced, replacement, mapLinIndx] = nicheCompete(newInds,fitness,map,d)
22
%nicheCompete - results of competition with map's existing elites
33
%
44
% Syntax: [replaced, replacement] = nicheCompete(newInds,fitness,map,p)
@@ -12,6 +12,7 @@
1212
% Outputs:
1313
% replaced - [NX1] - Linear index of map cells to recieve replacements
1414
% replacement - [NX1] - Index of newInds to replace current elites in niche
15+
% mapLinIndx - [NX1] - Index of current elites (for rank testing only)
1516
%
1617
% Example:
1718
%
@@ -28,8 +29,13 @@
2829
[bestIndex, bestBin] = getBestPerCell(newInds,fitness,d, map.edges);
2930
mapLinIndx = sub2ind(d.featureRes,bestBin(:,1),bestBin(:,2));
3031

32+
% Nan features?
33+
% A 'nan' genome sneaks in -- apparently after precise evaluation
34+
if any(isnan(mapLinIndx)); save('nanFeatureError'); end
35+
36+
3137
% Compare to already existing samples
32-
improvement = ~(fitness (bestIndex) >= map.fitness(mapLinIndx)); % comparisons to NaN are always false
38+
improvement = ~(fitness (bestIndex) >= map.fitness(mapLinIndx)); % comparisons to NaN are always false
3339
improvement(isnan(fitness(bestIndex))) = false;
3440
replacement = bestIndex (improvement);
3541
replaced = mapLinIndx(improvement);

runSail.m

+42-55
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,60 @@
1-
%runSail - Example usage script of sail function
2-
% Running sail without arguments will return a hyperparameter struct of
1+
%RUNSAIL - Example usage script of sail function
2+
% Calling sail without arguments will return a hyperparameter struct of
33
% default values. These defaults can be changed in
44
% /sail/defaultParamSet.m
55
%
6-
% Running sail with a parameter struct as input will run the algorithm
6+
% Calling sail with a parameter and domain struct as input will run the
7+
% algorithm.
78
%
8-
%
9-
% Other m-files required: defaultParamSet, sail, mapElites
10-
% Other submodules required: gpml-wrapper
9+
% Other m-files required: /sail/defaultParamSet.m, <domainName>_Domain.m
10+
% Other submodules required: gpml
11+
% For domain requirements see domains/<domainName>/Content.m
1112
%
1213
%
13-
% See also: mapElites, sail
14+
% See also: hpcSail, sail
1415

1516
% Author: Adam Gaier
1617
% Bonn-Rhein-Sieg University of Applied Sciences (HBRS)
1718
% email: adam.gaier@h-brs.de
18-
% Nov 2016; Last revision: 01-Aag-2017
19+
% Nov 2016; Last revision: 04-Dec-2017
1920

2021
%------------- BEGIN CODE --------------
21-
22-
p = sail;
23-
24-
% Adjust hyperparameters
25-
p.nInitialSamples = 50;
26-
p.nAdditionalSamples= 10;
27-
p.nTotalSamples = 150;
28-
p.nChildren = 100;
29-
p.nGens = 500;
22+
% Clean up workspace and add relevant files to path
23+
clear;
24+
currentPath = mfilename('fullpath');
25+
addpath(genpath(currentPath(1:end-length(mfilename))));
26+
27+
% Algorithm hyperparameters
28+
p = sail; % load default hyperparameters
29+
30+
% Edit Hyperparameters
31+
p.nInitialSamples = 100;
32+
p.nTotalSamples = 200;
33+
p.nChildren = 2^5;
34+
p.nGens = 2^6;
3035

31-
p.display.illu = false;
32-
p.display.illuMod = 100;
33-
p.display.figs = true;
36+
p.data.mapEval = false; % produce intermediate prediction maps?
37+
p.data.mapEvalMod = 50; % how often? (in samples)
3438

35-
p.data.outSave = false;
36-
p.data.mapEval = true;
37-
p.data.mapEvalMod = 50;
39+
% Domain
40+
%d = parsec_Domain;
41+
d = ffdFoil_Domain;
42+
%d = velo_Domain('encoding','ffd'); d.preciseEvaluate = 'velo_DummyPreciseEvaluate';
3843

39-
40-
% % % % % % % % % % % % % % %
41-
tic;
42-
%d = velo_Domain;
43-
d = af_Domain;
44+
%% Run SAIL
45+
runTime = tic;
4446
output = sail(p,d);
45-
disp(['Runtime: ' seconds2human(toc)]);
46-
47-
%% Create Prediction Map from produced surrogate
48-
% Adjust hyperparameters
49-
p.nChildren = 250;
50-
p.nGens = 500;
51-
52-
p.display.illu = true; p.display.illuMod = 100;
53-
54-
predMap = createPredictionMap(output.model,p,d,'featureRes',[50 50]);
55-
viewMap(predMap.fitness, d, predMap.edges) % View Prediction Map
56-
57-
58-
59-
60-
61-
62-
63-
64-
65-
66-
67-
68-
69-
70-
71-
47+
disp(['Runtime: ' seconds2human(toc(runTime))]);
7248

49+
%% Create New Prediction Map from produced surrogate
50+
%
51+
% % Adjust hyperparameters
52+
% p.nGens = 2*p.nGens;
53+
%
54+
% [predMap, percImproved] = createPredictionMap(...
55+
% output.model,... % Model for evaluation
56+
% output.model{1}.trainInput,... % Initial solutions
57+
% p,d,'featureRes',[25 25]); % Hyperparameters
58+
%
59+
% save('sailTest.mat','output','p','d','predMap','rTest');
7360

sail/createPredictionMap.m

+24-21
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
function predMap = createPredictionMap(gpModels,p,d, varargin)
1+
function [predMap, percImproved, rTest] = createPredictionMap(gpModels,observation,p,d, varargin)
22
%createPredictionMap - Produce prediction map from surrogate model
33
%
4-
% Syntax: predictionMap = createPredictionMap(gpModels,p,d)
4+
% Syntax: predictionMap = createPredictionMap(gpModels,observation,p,d)
55
%
66
% Inputs:
7-
% gpModels - GP model produced by SAIL
8-
% p - SAIL hyperparameter struct
9-
% d - Domain definition struct
7+
% gpModels - [cell] GP model(s) produced by SAIL
8+
% observation- [N X GenomeLength] Known inputs
9+
% p - [struct] SAIL hyperparameters
10+
% d - [struct] Domain definition
1011
%
1112
% Outputs:
1213
% predMap - prediction map
13-
% .fitness [Rows X Columns]
14-
% .genes [Rows X Columns X GenomeLength]
15-
% .'otherVals' [Rows X Columns]
14+
% .fitness [FeatureRes(1) X FeatureRes(2)]
15+
% .genes [FeatureRes(1) X FeatureRes(2) X GenomeLength]
16+
% .'otherVals' [FeatureRes(1) X FeatureRes(2)]
17+
% percImproved [1 X nGens] - percentage of children which improved on elites
1618
%
17-
% Example:
18-
% p = sail;
19-
% d = af_Domain;
19+
% Example:
20+
% p = sail; d = af_Domain;
2021
% output = sail(d,p);
21-
% predMap = createPredictionMap(output.model,p,d,'featureRes',[50 50]);
22-
% viewMap(predMap.fitness,d, predMap.edges)
22+
% predMap = createPredictionMap(output.model,output.model{1}.trainInput,p,d,'featureRes',[50 50]);
23+
% viewMap(predMap.fitness,d)
2324
%
2425
% Other m-files required: mapElites nicheCompete updateMap d.createAcqFunction
2526
%
@@ -28,18 +29,20 @@
2829
% Author: Adam Gaier
2930
% Bonn-Rhein-Sieg University of Applied Sciences (BRSU)
3031
% email: adam.gaier@h-brs.de
31-
% Jun 2017; Last revision: 03-Aug-2017
32+
% Jun 2017; Last revision: 01-Sep-2017
3233

34+
%% TODO: if no observations given take them from the gpModels
3335
%------------- INPUT PARSING -----------
3436
parse = inputParser;
3537
parse.addRequired('gpModels');
3638
parse.addRequired('p');
3739
parse.addRequired('d');
38-
parse.addOptional('nChildren',p.nChildren);
39-
parse.addOptional('nGens',p.nGens);
40-
parse.addOptional('featureRes',d.featureRes);
40+
parse.addRequired('observation');
41+
parse.addOptional('nChildren' ,p.nChildren);
42+
parse.addOptional('nGens' ,p.nGens);
43+
parse.addOptional('featureRes' ,d.featureRes);
4144

42-
parse.parse(gpModels,p,d,varargin{:});
45+
parse.parse(gpModels, observation, p, d, varargin{:});
4346
p.nChildren = parse.Results.nChildren;
4447
p.nGens = parse.Results.nGens;
4548
d.featureRes = parse.Results.featureRes;
@@ -51,14 +54,14 @@
5154
acqFunction = feval(d.createAcqFunction,gpModels,d);
5255

5356
% Seed map with precisely evaluated solutions
54-
observation = gpModels{1}.trainInput;
5557
[fitness,predValues] = acqFunction(observation);
5658
predMap = createMap(d.featureRes, d.dof, d.extraMapValues);
5759
[replaced, replacement] = nicheCompete(observation, fitness, predMap, d);
5860
predMap = updateMap(replaced,replacement,predMap,fitness,observation,...
59-
predValues,d.extraMapValues);
61+
predValues,d.extraMapValues);
6062

6163
% Illuminate based on surrogate models
62-
predMap = mapElites(acqFunction,predMap,p,d);
64+
[predMap, percImproved] = mapElites(acqFunction,predMap,p,d);
65+
6366

6467
%------------- END OF CODE --------------

0 commit comments

Comments
 (0)