├── .gitattributes ├── readme_img ├── input.png └── output.png ├── src ├── utils │ ├── get_chunk.m │ ├── get_struct_idx.m │ ├── get_struct_size.m │ └── get_struct_assemble.m ├── optim │ ├── bruteforce.m │ ├── get_vectorized.m │ ├── get_solution.m │ └── get_pre_proc.m └── get_multi_obj_opt.m ├── LICENSE.md ├── run_example.m ├── README.md └── get_data.m /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /readme_img/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ethz-pes/multi_objective_optimization_matlab/HEAD/readme_img/input.png -------------------------------------------------------------------------------- /readme_img/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ethz-pes/multi_objective_optimization_matlab/HEAD/readme_img/output.png -------------------------------------------------------------------------------- /src/utils/get_chunk.m: -------------------------------------------------------------------------------- 1 | function [n_chunk, idx_chunk] = get_chunk(n_size, n_split) 2 | %GET_CHUNK Split data into chunks with maximum size. 3 | % [n_chunk, idx_chunk] = GET_CHUNK(n_size, n_split) 4 | % n_size - number of data to be splitted in chunks (integer) 5 | % n_split - number of data per chunk (integer) 6 | % n_chunk - number of created chunks (integer) 7 | % idx_chunk - cell with the indices of the chunks (cell of array of indices) 8 | % 9 | % The division of computational data is useful: 10 | % - Dividing the data for parallel loop (loop) 11 | % - Reducing the data in the memory while computing 12 | % 13 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 14 | 15 | % init the data 16 | idx = 1; 17 | idx_chunk = {}; 18 | 19 | % create the chunks indices 20 | while idx<=n_size 21 | idx_new = min(idx+n_split,n_size+1); 22 | vec = idx:(idx_new-1); 23 | idx_chunk{end+1} = vec; 24 | idx = idx_new; 25 | end 26 | 27 | % count the chunks 28 | n_chunk = length(idx_chunk); 29 | 30 | end -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-2020 ETH Zurich, Power Electronic Systems Laboratory, T. Guillod. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDi 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /src/utils/get_struct_idx.m: -------------------------------------------------------------------------------- 1 | function struct_out = get_struct_idx(struct_in, idx) 2 | %GET_STRUCT_IDX Get specified indices in a struct of arrays. 3 | % struct_out = GET_STRUCT_IDX(struct_in, idx) 4 | % struct_in - input struct to be sliced (struct of arrays) 5 | % idx - indices to be selected (array of indices or array of logical) 6 | % struct_out - output struct with the selected indices (struct of arrays) 7 | % 8 | % The input struct should have some properties: 9 | % - Struct can be nested (the function is recursive) 10 | % - The values of the struct should be 'numeric' or 'logical' arrays 11 | % - The values are selected with respect to the provided indices 12 | % - The arrays are row arrays. 13 | % 14 | % See also GET_STRUCT_SIZE, GET_STRUCT_ASSEMBLE. 15 | % 16 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 17 | 18 | % init the data 19 | struct_out = struct(); 20 | field = fieldnames(struct_in); 21 | 22 | % for each field 23 | for i=1:length(field) 24 | struct_in_tmp = struct_in.(field{i}); 25 | if isstruct(struct_in_tmp) 26 | % for struct, recursion 27 | struct_out.(field{i}) = get_struct_idx(struct_in_tmp, idx); 28 | else 29 | % for values, slicing with indices 30 | assert(isnumeric(struct_in_tmp)||islogical(struct_in_tmp), 'invalid type') 31 | struct_out.(field{i}) = struct_in_tmp(idx); 32 | end 33 | end 34 | 35 | end -------------------------------------------------------------------------------- /src/utils/get_struct_size.m: -------------------------------------------------------------------------------- 1 | function struct_out = get_struct_size(struct_in, n_size) 2 | %GET_STRUCT_SIZE Expand a struct of scalars to a struct of arrays. 3 | % struct_out = GET_STRUCT_SIZE(struct_in, n_size) 4 | % struct_in - input struct to be expanded (struct of scalars) 5 | % n_size - desired size for the arrays (integer) 6 | % struct_out - output struct of arrays (struct of arrays) 7 | % 8 | % The input struct should have some properties: 9 | % - Struct can be nested (the function is recursive) 10 | % - The values of the struct should be 'numeric' or 'logical' scalars 11 | % - The values are transformed into arrays with repmat 12 | % - The arrays are row arrays. 13 | % 14 | % See also GET_STRUCT_IDX, GET_STRUCT_ASSEMBLE. 15 | % 16 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 17 | 18 | % init the data 19 | struct_out = struct(); 20 | field = fieldnames(struct_in); 21 | 22 | % for each field 23 | for i=1:length(field) 24 | struct_in_tmp = struct_in.(field{i}); 25 | if isstruct(struct_in_tmp) 26 | % for struct, recursion 27 | struct_out.(field{i}) = get_struct_size(struct_in_tmp, n_size); 28 | else 29 | % for values, expansion 30 | assert(isnumeric(struct_in_tmp)||islogical(struct_in_tmp), 'invalid type') 31 | assert(length(struct_in_tmp)==1, 'invalid length') 32 | struct_out.(field{i}) = repmat(struct_in_tmp, [1, n_size]); 33 | end 34 | end 35 | 36 | end -------------------------------------------------------------------------------- /src/utils/get_struct_assemble.m: -------------------------------------------------------------------------------- 1 | function struct_out = get_struct_assemble(struct_in, n_size) 2 | %GET_STRUCT_ASSEMBLE Assemble array of struct of arrays into a struct of arrays. 3 | % struct_out = GET_STRUCT_ASSEMBLE(struct_in) 4 | % struct_in - input array of struct to be concatenated (array of struct of arrays) 5 | % n_size - desired size for the arrays (integer) 6 | % struct_out - output struct of arrays (struct of arrays) 7 | % 8 | % The input array of struct should have some properties: 9 | % - Struct can be nested (the function is recursive) 10 | % - The values of the struct should be 'numeric' or 'logical' arrays 11 | % - The values are concatenated respecting the input order 12 | % - The arrays are row arrays. 13 | % 14 | % See also GET_STRUCT_IDX, GET_STRUCT_SIZE. 15 | % 16 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 17 | 18 | % init the data 19 | struct_out = struct(); 20 | field = fieldnames(struct_in); 21 | 22 | % for each field 23 | for i=1:length(field) 24 | % concatenate the structs 25 | struct_in_tmp = [struct_in.(field{i})]; 26 | 27 | if isstruct(struct_in_tmp) 28 | % for struct, recursion 29 | struct_out.(field{i}) = get_struct_assemble(struct_in_tmp, n_size); 30 | else 31 | % for values, assign 32 | assert(isnumeric(struct_in_tmp)||islogical(struct_in_tmp), 'invalid type') 33 | assert(size(struct_in_tmp, 2)==n_size, 'invalid type') 34 | struct_out.(field{i}) = struct_in_tmp; 35 | end 36 | end 37 | 38 | end -------------------------------------------------------------------------------- /run_example.m: -------------------------------------------------------------------------------- 1 | function run_example() 2 | %RUN_EXAMPLE Run an example of multi-ojective optimization with different solvers. 3 | % 4 | % The description of the problem can be found in 'get_data'. 5 | % 6 | % See also GET_MULTI_OBJ_OPT, GET_DATA. 7 | % 8 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 9 | 10 | close('all') 11 | addpath(genpath('src')) 12 | 13 | %% solve brute force optimization 14 | [var_param, solver_param] = get_data('bruteforce'); 15 | data_bruteforce = get_multi_obj_opt('bruteforce', var_param, solver_param); 16 | 17 | %% solve single-objective optimization with genetic algorithm 18 | [var_param, solver_param] = get_data('ga'); 19 | data_ga = get_multi_obj_opt('ga', var_param, solver_param); 20 | 21 | %% solve multi-objective optimization with genetic algorithm 22 | [var_param, solver_param] = get_data('gamultiobj'); 23 | data_gamultiobj = get_multi_obj_opt('gamultiobj', var_param, solver_param); 24 | 25 | %% plot the results 26 | figure() 27 | plot3(data_bruteforce.sol.input.x_1, data_bruteforce.sol.input.x_2, data_bruteforce.sol.input.x_3, 'xb') 28 | hold('on') 29 | plot3(data_gamultiobj.sol.input.x_1, data_gamultiobj.sol.input.x_2, data_gamultiobj.sol.input.x_3, 'dr') 30 | plot3(data_ga.sol.input.x_1, data_ga.sol.input.x_2, data_ga.sol.input.x_3, 'og', 'markerfacecolor', 'g') 31 | grid('on') 32 | xlabel('x_{1}') 33 | ylabel('x_{2}') 34 | zlabel('x_{3}') 35 | legend({'bruteforce', 'gamultiobj', 'ga'}, 'Location', 'northeast') 36 | title('Multi-Objective Optimization / Input') 37 | 38 | figure() 39 | plot(data_bruteforce.sol.output.y_1, data_bruteforce.sol.output.y_2, 'xb') 40 | hold('on') 41 | plot(data_gamultiobj.sol.output.y_1, data_gamultiobj.sol.output.y_2, 'dr') 42 | plot(data_ga.sol.output.y_1, data_ga.sol.output.y_2, 'og', 'markerfacecolor', 'g') 43 | grid('on') 44 | xlabel('y_{1}') 45 | ylabel('y_{2}') 46 | legend({'bruteforce', 'gamultiobj', 'ga'}, 'Location', 'northeast') 47 | title('Multi-Objective Optimization / Output') 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /src/optim/bruteforce.m: -------------------------------------------------------------------------------- 1 | function [x, fval, exitflag, output] = bruteforce(fct_obj, x0, lb, ub, fct_con, options) 2 | %BRUTEFORCE Brute force grid search optimization algorithm. 3 | % [x, fval, exitflag, output] = BRUTEFORCE(fct_obj, x0, lb, ub, fct_con, options) 4 | % fct_obj - objective function for the optimization (function handle) 5 | % fval = fct_obj(x) 6 | % x - input points (matrix) 7 | % fval - objective function values (matrix or array) 8 | % x0 - input points to be considered (matrix) 9 | % lb - lower bound for the different variables (array or empty) 10 | % ub - upper bound for the different variables (array or empty) 11 | % fct_con - function with equalities and inequalities constraints (function handle) 12 | % [c, ceq] = fct_con(x0) 13 | % x - input points (matrix) 14 | % c - inequalities contraints, c<0 (matrix or array or empty) 15 | % ceq - equalities contraints, c==0 (matrix or array or empty) 16 | % options - strut with the tolerances on the constraints (struct) 17 | % options.ConstraintToleranceInEq - tolerance for inequalities (float) 18 | % options.ConstraintToleranceEq - tolerance for equalities (float) 19 | % x - output valid points (matrix) 20 | % fval - objective function values of the valid points (matrix or array) 21 | % exitflag - return status of the solver (integer) 22 | % 1 - valid points are found 23 | % 0 - no valid points 24 | % output - struct with information about the solver (struct) 25 | % options.n_sim - number of input points (integer) 26 | % options.n_valid - number of valid points (integer) 27 | % 28 | % This solver works with vectorized data: 29 | % - n_col - number of variables 30 | % - n_row - number of points 31 | % 32 | % The input and output arguments are strange for a brute force solver. 33 | % This has been done in order to have similar arguments as the MATLAB optimization toolbox. 34 | % 35 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 36 | 37 | % number of points 38 | n_sim = size(x0, 1); 39 | 40 | % compute constraints 41 | lb = repmat(lb, n_sim, 1); 42 | ub = repmat(ub, n_sim, 1); 43 | [c, ceq] = fct_con(x0); 44 | 45 | % extract the valid points 46 | idx = true(n_sim, 1); 47 | if (~isempty(lb)) 48 | idx = idx&all(x0>=lb, 2); 49 | end 50 | if (~isempty(ub)) 51 | idx = idx&all(x0<=ub, 2); 52 | end 53 | if (~isempty(c)) 54 | idx = idx&all(c0); 71 | 72 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MATLAB Tool for Multi-Objective Optimization 2 | 3 | ![license - BSD](https://img.shields.io/badge/license-BSD-green) 4 | ![language - MATLAB](https://img.shields.io/badge/language-MATLAB-blue) 5 | ![category - science](https://img.shields.io/badge/category-science-lightgrey) 6 | ![status - unmaintained](https://img.shields.io/badge/status-unmaintained-red) 7 | 8 | This **MATLAB** tool offers different functionalities for multi-objective optimization: 9 | * Offer a **common interface** for different solvers 10 | * **Brute force** grid search (exhaustive search) 11 | * MATLAB **single-objective genetic** algorithm ('ga') 12 | * MATLAB **multi-objective genetic** algorithm ('gamultiobj') 13 | * Offer an **abstraction layer** to the MATLAB solver 14 | * Scaling the input variables 15 | * Generating and filtering initial points 16 | * Transforming high-level data structures ('struct') to low-level ('matrix') 17 | * Generating the low-level inputs required by the solvers 18 | * Allow **vectorized and parallel** evaluation of the functions 19 | * Divide the number of points to be evaluated into chunks 20 | * Evaluate the chunks with parallel computing ('parfor') 21 | * The points inside a chunk are evaluated in a vectorized way 22 | 23 | Mathematically, the following optimization problems are solved: 24 | * Multiple variables 25 | * Integer variables 26 | * Upper and lower bounds 27 | * Inequality constraints 28 | * Equality constraints 29 | * Non continuous objective function 30 | * Single-objective or multi-objective goals 31 | 32 | ## Example 33 | 34 | Look at the example [run_example.m](run_example.m) which generates the following results: 35 | 36 |

37 | 38 | 39 |

40 | 41 | ## Adding Solvers 42 | 43 | The code is made to take advantage of optimization methods using vectorized evaluation of the objective function. 44 | Therefore, it would be easy to add support for 'patternsearch', 'particleswarm', or 'paretosearch'. 45 | Adding support for non vectorized solvers ('fmincon', 'fminbnd', or 'fminsearch') is possible but less interesting. 46 | 47 | ## Compatibility 48 | 49 | * Tested with MATLAB R2018b. 50 | * The `gads_toolbox` is required (for the MATLAB solvers). 51 | * The `optimization_toolbox` is required (for the MATLAB solvers). 52 | * The `distrib_computing_toolbox` is required (for parfor loops) 53 | * Compatibility with GNU Octave not tested but probably problematic. 54 | 55 | ## Author 56 | 57 | * **Thomas Guillod, ETH Zurich, Power Electronic Systems Laboratory** - [GitHub Profile](https://github.com/otvam) 58 | 59 | ## License 60 | 61 | * This project is licensed under the **BSD License**, see [LICENSE.md](LICENSE.md). 62 | * This project is copyrighted by: (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod. 63 | -------------------------------------------------------------------------------- /src/get_multi_obj_opt.m: -------------------------------------------------------------------------------- 1 | function data = get_multi_obj_opt(name, var_param, solver_param) 2 | %GET_MULTI_OBJ_OPT Solve a multi-objective optimization problem with different solvers. 3 | % data = GET_MULTI_OBJ_OPT(name, var_param, solver_param) 4 | % name - name of the problem (string) 5 | % var_param - struct with the variable description (struct) 6 | % solver_param - struct with the solver data (struct) 7 | % data - struct containing the solution (struct) 8 | % data.n_var - number of input variables used for the optimization (integer) 9 | % data.n_init - number of initial points used by the algorithm (integer) 10 | % data.n_sol - number points contained in the solution (integer) 11 | % data.has_converged - return status of the algorithm (boolean) 12 | % data.info - information from the solver about the convergence (struct) 13 | % data.info.output - struct with information about the solver (struct) 14 | % data.info.exitflag - return status of the solver (integer) 15 | % data.sol - solution data (struct) 16 | % data.sol.fval - values of the objective function (array of matrix) 17 | % data.sol.input - struct with the valid points (struct of arrays) 18 | % data.sol.output - struct with the generated output (struct of arrays) 19 | % 20 | % For more information about 'data.var_param', see 'get_pre_proc'. 21 | % For more information about 'data.solver_param', see 'get_solution'. 22 | % 23 | % This multi-objective optimization works in two steps: 24 | % - 'get_pre_proc' - extract and scale the variables, get the intial points 25 | % - 'get_solution' - solve the problem with different solvers 26 | % 27 | % The following solver are currently implemented: 28 | % - 'bruteforce' - check and the intial points and nothing else 29 | % - 'ga' - single-objective genetic optimization 30 | % - 'gamultiobj' - multi-objective genetic optimization 31 | % 32 | % See also GET_PRE_PROC, GET_SOLUTION. 33 | % 34 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 35 | 36 | % init the simulation 37 | disp(['============================= ' name]) 38 | 39 | % parse the optimization variables 40 | disp('pre_proc') 41 | [optim, n_var, n_init] = get_pre_proc(var_param); 42 | 43 | % display the number of variables and initial points 44 | disp('disp pre_proc') 45 | disp([' n_var = ' num2str(n_var)]) 46 | disp([' n_init = ' num2str(n_init)]) 47 | 48 | % solve the optimization problem 49 | disp('solution') 50 | [sol, n_sol, has_converged, info] = get_solution(solver_param, optim); 51 | 52 | % display the number of solution and some other information 53 | disp('disp solution') 54 | disp([' n_var = ' num2str(n_var)]) 55 | disp([' n_init = ' num2str(n_init)]) 56 | disp([' n_sol = ' num2str(n_sol)]) 57 | disp([' has_converged = ' num2str(has_converged)]) 58 | 59 | % assign the results 60 | data.n_var = n_var; 61 | data.n_init = n_init; 62 | data.n_sol = n_sol; 63 | data.has_converged = has_converged; 64 | data.info = info; 65 | data.sol = sol; 66 | 67 | end -------------------------------------------------------------------------------- /src/optim/get_vectorized.m: -------------------------------------------------------------------------------- 1 | function sol = get_vectorized(x, fct_input, fct_sol, n_split) 2 | %GET_VECTORIZED Compute a function with parallel and vectorized evaluation. 3 | % sol = GET_VECTORIZED(x, fct_input, fct_sol, n_split) 4 | % x - input points to be evaluated (matrix) 5 | % fct_input - input points to be evaluated (function handle) 6 | % [input, n_size] = fct_input(x) 7 | % x - input points to be evaluated (matrix) 8 | % input - parsed and scaled input points (struct of arrays) 9 | % n_size - number of points (integer) 10 | % fct_sol - compute the solution from the input (function handle) 11 | % sol = fct_sol(input, n_size); 12 | % input - parsed and scaled input points (struct of arrays) 13 | % n_size - number of points (integer) 14 | % sol - computed solution (matrix or array or struct of arrays) 15 | % n_split - maximum number of solution evaluated in one vectorized call (integer) 16 | % sol - computed solution (matrix or array or struct of arrays) 17 | % 18 | % The following steps are computed: 19 | % - Unscale the variables to get the points to be computed with 'fct_input' 20 | % - Split the points into chunks for parallel evaluation 21 | % - Compute the points (parallel / vectorized) with 'fct_sol' 22 | % - Assemble the different chunks together 23 | % 24 | % See also GET_SOLUTION, GET_CHUNK. 25 | % 26 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 27 | 28 | % parse and unscale the variable 29 | disp(' get var') 30 | [input, n_size] = fct_input(x); 31 | 32 | if isnan(n_split)||(n_size<=n_split) 33 | % if too little points, compute without parallel chunks 34 | disp([' solve / ' num2str(n_size)]) 35 | sol = fct_sol(input, n_size); 36 | else 37 | % divide the points into chunks 38 | disp([' chunk / ' num2str(n_size)]) 39 | [n_chunk, idx_chunk] = get_chunk(n_size, n_split); 40 | 41 | % parallel computing of the different chunks 42 | parfor i=1:n_chunk 43 | disp([' ' num2str(i) ' / ' num2str(n_chunk)]) 44 | sol{i} = get_sol_vec(input, fct_sol, idx_chunk{i}); 45 | end 46 | 47 | % assemble the chunks together 48 | disp(' assemble') 49 | sol = [sol{:}]; 50 | if isstruct(sol) 51 | sol = get_struct_assemble(sol, n_size); 52 | else 53 | assert(isnumeric(sol)||islogical(sol), 'invalid type') 54 | assert((size(sol, 2)==n_size)||isempty(sol), 'invalid size') 55 | end 56 | end 57 | 58 | end 59 | 60 | function sol = get_sol_vec(input, fct_sol, idx_chunk) 61 | %GET_SOL_VEC Compute the solution for a specific chunk. 62 | % sol = GET_SOL_VEC(input, fct_sol, idx_chunk)) 63 | % input - parsed and scaled input points (struct of arrays) 64 | % fct_sol - compute the solution from the input (function handle) 65 | % idx_chunk - indices of the combination to be computed (array of indices) 66 | % sol - computed solution (matrix or array or struct of arrays) 67 | 68 | % select the combination with respect to the chunk 69 | input = get_struct_idx(input, idx_chunk); 70 | 71 | % compute the solutions 72 | sol = fct_sol(input, nnz(idx_chunk)); 73 | 74 | end -------------------------------------------------------------------------------- /src/optim/get_solution.m: -------------------------------------------------------------------------------- 1 | function [sol, n_sol, has_converged, info] = get_solution(solver_param, optim) 2 | %GET_SOLUTION Solve the multi-objective optimization problem with different solvers. 3 | % [sol, n_sol, n_sim, has_converged, info] = GET_SOLUTION(solver_param, optim) 4 | % solver_param.solver_param - struct with the solver data (struct) 5 | % solver_name - name of the solver (string) 6 | % 'bruteforce' - test all the initial points, nothing more 7 | % 'ga' - MATLAB genetic algorithm 'ga' 8 | % 'gamultiobj' - MATLAB genetic algorithm 'gamultiobj' 9 | % solver_param.n_split - maximum number of solution evaluated in one vectorized call (integer) 10 | % solver_param.options - options for the solver (GaOptions or GamultiobjOptions or struct) 11 | % fct_obj - compute the objective value from the input (function handle) 12 | % fval = fct_obj(input, n_size); 13 | % input - parsed and scaled input points (struct of arrays) 14 | % n_size - number of points (integer) 15 | % fval - objective function (matrix or array) 16 | % fct_con_c - compute the inequalities contraints from the input (function handle) 17 | % c = fct_obj(input, n_size); 18 | % input - parsed and scaled input points (struct of arrays) 19 | % n_size - number of points (integer) 20 | % c - inequalities contraints, c<0 (matrix or empty) 21 | % fct_con_ceq - compute the equalities contraints from the input (function handle) 22 | % ceq = fct_obj(input, n_size); 23 | % input - parsed and scaled input points (struct of arrays) 24 | % n_size - number of points (integer) 25 | % ceq - equalities contraints, ceq==0 (matrix or empty) 26 | % fct_output - compute the output struct from the input (function handle) 27 | % output = fct_obj(input, n_size); 28 | % input - parsed and scaled input points (struct of arrays) 29 | % n_size - number of points (integer) 30 | % output - struct with the generated output (struct of arrays) 31 | % optim - struct with the parsed variables (struct) 32 | % optim.lb - array containing the lower bounds of the variables (array) 33 | % optim.ub - array containing the upper bounds of the variables (array) 34 | % optim.int_con - array containing the index of the integer variables (array of indices) 35 | % optim.input - struct containing the constant (non-optimized) variables (struct of scalars) 36 | % optim.x0 - matrix containing the scaled initial points (matrix) 37 | % optim.fct_input - function creating the input struct from the scaled variables (function handle) 38 | % [input, n_size] = fct_input(x) 39 | % x - input points to be evaluated (matrix) 40 | % input - parsed and scaled input points (struct of arrays) 41 | % n_size - number of points (integer) 42 | % sol - solution data (struct) 43 | % sol.fval - values of the objective function (array of matrix) 44 | % sol.input - struct with the valid points (struct of arrays) 45 | % sol.output - struct with the generated output (struct of arrays) 46 | % n_sol - number points contained in the solution (integer) 47 | % has_converged - return status of the algorithm (boolean) 48 | % info - information from the solver about the convergence (struct) 49 | % info.output - struct with information about the solver (struct) 50 | % info.exitflag - return status of the solver (integer) 51 | % 52 | % This function performs optimization with different solvers. 53 | % Please note that the 'gamultiobj' cannot deal with integer variables. 54 | % 55 | % See also GET_MULTI_OBJ_OPT, GET_PRE_PROC, GET_VECTORIZED, BRUTEFORCE, GA GAMULTIOBJ. 56 | % 57 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 58 | 59 | % extract 60 | solver_name = solver_param.solver_name; 61 | fct_output = solver_param.fct_output; 62 | fct_obj = solver_param.fct_obj; 63 | fct_con_c = solver_param.fct_con_c; 64 | fct_con_ceq = solver_param.fct_con_ceq; 65 | n_split = solver_param.n_split; 66 | options = solver_param.options; 67 | fct_input = optim.fct_input; 68 | x0 = optim.x0; 69 | lb = optim.lb; 70 | ub = optim.ub; 71 | int_con = optim.int_con; 72 | 73 | % get the functions with vectorized / parallel evaluation 74 | % transpose the values such that n_row is the number of points 75 | fct_obj_tmp = @(x) get_vectorized(x, fct_input, fct_obj, n_split).'; 76 | fct_con_c_tmp = @(x) get_vectorized(x, fct_input, fct_con_c, n_split).'; 77 | fct_con_ceq_tmp = @(x) get_vectorized(x, fct_input, fct_con_ceq, n_split).'; 78 | fct_output_tmp = @(x) get_vectorized(x, fct_input, fct_output, n_split); 79 | 80 | % get the constraint function 81 | fct_con_tmp = @(x) deal(fct_con_c_tmp(x), fct_con_ceq_tmp(x)); 82 | 83 | % select the solver and go 84 | disp(' run optimization') 85 | switch solver_name 86 | case 'bruteforce' 87 | [x, fval, exitflag, output] = bruteforce(fct_obj_tmp, x0, lb, ub, fct_con_tmp, options); 88 | has_converged = (exitflag==1)&&isnumeric(x)&&isnumeric(fval); 89 | case 'ga' 90 | n_var = size(x0, 2); 91 | options = optimoptions(options, 'InitialPopulation', x0); 92 | options = optimoptions(options, 'OutputFcn', @output_fct_ga); 93 | options = optimoptions(options, 'Vectorized', 'on'); 94 | options = optimoptions(options, 'Display', 'off'); 95 | [x, fval, exitflag, output] = ga(fct_obj_tmp, n_var, [], [], [], [], lb, ub, fct_con_tmp, int_con, options); 96 | has_converged = any(exitflag==[0 1 3 4 5])&&isnumeric(x)&&isnumeric(fval); 97 | case 'gamultiobj' 98 | n_var = size(x0, 2); 99 | options = optimoptions(options, 'InitialPopulation', x0); 100 | options = optimoptions(options, 'OutputFcn', @output_fct_ga); 101 | options = optimoptions(options, 'Vectorized', 'on'); 102 | options = optimoptions(options, 'Display', 'off'); 103 | assert(isempty(int_con), 'invalid constraints') 104 | [x, fval, exitflag, output] = gamultiobj(fct_obj_tmp, n_var, [], [], [], [], lb, ub, fct_con_tmp, options); 105 | has_converged = any(exitflag==[0 1])&&isnumeric(x)&&isnumeric(fval); 106 | otherwise 107 | error('invalid solver_name') 108 | end 109 | 110 | % get the convergence info 111 | disp(' eval convergence') 112 | n_sol = size(x, 1); 113 | info.output = output; 114 | info.exitflag = exitflag; 115 | 116 | % get the solution for the optimal point 117 | disp(' eval solution') 118 | sol.fval = fval; 119 | sol.input = fct_input(x); 120 | sol.output = fct_output_tmp(x); 121 | 122 | end 123 | 124 | function [state, options, optchanged] = output_fct_ga(options, state, flag) 125 | %OUTPUT_FCN Display function for the genetic algorithms. 126 | % [state, options, optchanged] = OUTPUT_FCN(options, state, flag) 127 | % options - options of the genetic algorithm (optim object) 128 | % state - state information about the solver (struct) 129 | % flag - string with the iteration type (string) 130 | % optchanged - switch if the options are updated (boolean) 131 | 132 | optchanged = false; 133 | disp([' ' flag ' / ' num2str(state.Generation) ' / ' num2str(state.FunEval)]) 134 | 135 | end -------------------------------------------------------------------------------- /get_data.m: -------------------------------------------------------------------------------- 1 | function [var_param, solver_param] = get_data(solver_name) 2 | %GET_DATA Get the data for a (example) multi-objective optimization problem. 3 | % [var_param, solver_param] = get_data(solver_name) 4 | % var_param - struct with the variable description (struct) 5 | % solver_param - struct with the solver data (struct) 6 | % 7 | % Solve an optimization problem with: 8 | % - Multiple variables 9 | % - Integer variables 10 | % - Upper and lower bounds 11 | % - Inequality constraints 12 | % - Equality constraints 13 | % - Non continuous objective function 14 | % - Single-objective or multi-objective goals 15 | % 16 | % Use the followig strategies: 17 | % - brute force grid search (mixed integer) 18 | % - single-objective genetic algorithm (mixed integer) 19 | % - multi-objective genetic algorithm (continuous variables) 20 | % 21 | % The problem solved in this example is trivial and not very interesting. 22 | % 23 | % See also RUN_OPTIM, GET_MULTI_OBJ_OPT, GET_PRE_PROC, GET_SOLUTION. 24 | % 25 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 26 | 27 | switch solver_name 28 | case 'bruteforce' 29 | var_param = get_var_param('mixed_integer'); 30 | 31 | options = struct('ConstraintToleranceEq', 1e-3, 'ConstraintToleranceInEq', 1e-3); 32 | solver_param = get_solver_param('single_objective', solver_name, options); 33 | case 'ga' 34 | var_param = get_var_param('mixed_integer'); 35 | 36 | options = optimoptions (@ga); 37 | options = optimoptions(options, 'TolFun', 1e-6); 38 | options = optimoptions(options, 'ConstraintTolerance', 1e-3); 39 | options = optimoptions(options, 'Generations', 20); 40 | options = optimoptions(options, 'PopulationSize', 2000); 41 | solver_param = get_solver_param('single_objective', solver_name, options); 42 | case 'gamultiobj' 43 | var_param = get_var_param('continuous'); 44 | 45 | options = optimoptions(@gamultiobj); 46 | options = optimoptions(options, 'TolFun', 1e-6); 47 | options = optimoptions(options, 'ConstraintTolerance', 1e-3); 48 | options = optimoptions(options, 'Generations', 20); 49 | options = optimoptions(options, 'PopulationSize', 700); 50 | solver_param = get_solver_param('multi_objective', solver_name, options); 51 | otherwise 52 | error('invalid solver_name') 53 | end 54 | 55 | end 56 | 57 | function var_param = get_var_param(type) 58 | %GET_VAR_PARAM Get the data for a (example) multi-objective optimization problem. 59 | % var_param = GET_VAR_PARAM(type) 60 | % type - type of the variables (string) 61 | % 'mixed_integer' - problem with integer variable 62 | % 'continuous' - problem without integer variable 63 | % var_param - struct with the variable description (struct) 64 | 65 | % variables list 66 | var = {}; 67 | var{end+1} = struct('type', 'float', 'name', 'x_1', 'scale', 'lin', 'vec', linspace(0, 3, 25), 'lb', 0.0, 'ub', 3.0); 68 | var{end+1} = struct('type', 'float', 'name', 'x_2', 'scale', 'log', 'vec', logspace(log10(1), log10(3), 25), 'lb', 1.0, 'ub', 3.0); 69 | switch type 70 | case 'mixed_integer' 71 | var{end+1} = struct('type', 'integer', 'name', 'x_3','vec', [5 7 9], 'set', [5 7 9]); 72 | case 'continuous' 73 | var{end+1} = struct('type', 'scalar', 'name', 'x_3', 'v', 5); 74 | otherwise 75 | error('invalid type') 76 | end 77 | var{end+1} = struct('type', 'scalar', 'name', 'x_4', 'v', 2); 78 | 79 | % assign 80 | var_param.var = var; % cell of struct with the different variable description 81 | var_param.n_max = 100e3; % maximum number of initial points for avoid out of memory crashes 82 | var_param.fct_select = @(input, n_size) true(1, n_size); % check if the generated iniitial points should be included 83 | 84 | end 85 | 86 | function solver_param = get_solver_param(type, solver_name, options) 87 | %GET_SOLVER_PARAM Get the data for a (example) multi-objective optimization problem. 88 | % solver_param = GET_SOLVER_PARAM(type, solver_name, options) 89 | % type - type of the problem (string) 90 | % 'single_objective' - scalar valued ojective function 91 | % 'multi_objective' - vector valued ojective function 92 | % solver_name - name of the solver (string) 93 | % options - options for the solver (GaOptions or GamultiobjOptions or struct) 94 | % solver_param - struct with the solver data (struct) 95 | 96 | solver_param.solver_name = solver_name; % name of the solver 97 | solver_param.options = options; % options for the solver 98 | solver_param.n_split = 500; % maximum number of solution evaluated in one vectorized call 99 | solver_param.fct_output = @get_output; % compute the output struct from the input 100 | solver_param.fct_con_c = @get_con_c; % compute the inequalities contraints from the input 101 | solver_param.fct_con_ceq = @get_con_ceq; % compute the equalities contraints from the input 102 | switch type 103 | case 'single_objective' 104 | solver_param.fct_obj = @get_obj_single; % compute the objective value from the input 105 | case 'multi_objective' 106 | solver_param.fct_obj = @get_obj_multi; % compute the objective value from the input 107 | otherwise 108 | error('invalid type') 109 | end 110 | 111 | end 112 | 113 | function c = get_con_c(input, n_size) 114 | %GET_CON_C Compute the inequalities contraints from the input. 115 | % c = GET_CON_C(input, n_size) 116 | % input - parsed and scaled input points (struct of arrays) 117 | % n_size - number of points (integer) 118 | % c - inequalities contraints, c<0 (matrix or empty) 119 | 120 | [y_1, y_2] = get_raw(input); 121 | c = [y_1-10 ; y_2-10]; 122 | 123 | end 124 | 125 | function ceq = get_con_ceq(input, n_size) 126 | %GET_CON_CEQ Compute the equalities contraints from the input. 127 | % ceq = GET_CON_CEQ(input, n_size) 128 | % input - parsed and scaled input points (struct of arrays) 129 | % n_size - number of points (integer) 130 | % ceq - equalities contraints, ceq==0 (matrix or empty) 131 | 132 | ceq = []; 133 | 134 | end 135 | 136 | 137 | function fval = get_obj_single(input, n_size) 138 | %GET_OBJ_SINGLE Compute the single-objective value from the input. 139 | % fval = GET_OBJ_SINGLE(input, n_size) 140 | % input - parsed and scaled input points (struct of arrays) 141 | % n_size - number of points (integer) 142 | % fval - objective function (array) 143 | 144 | [y_1, y_2] = get_raw(input); 145 | fval = y_1+y_2; 146 | 147 | end 148 | 149 | function fval = get_obj_multi(input, n_size) 150 | %GET_OBJ_MULTI Compute the multi-objective values from the input. 151 | % fval = GET_OBJ_MULTI(input, n_size) 152 | % input - parsed and scaled input points (struct of arrays) 153 | % n_size - number of points (integer) 154 | % fval - objective function (matrix) 155 | 156 | [y_1, y_2] = get_raw(input); 157 | fval = [y_1 ; y_2]; 158 | 159 | end 160 | 161 | function sol = get_output(input, n_size) 162 | %GET_OBJ_OUTPUT Compute the output struct from the input. 163 | % sol = GET_OBJ_OUTPUT(input, n_size) 164 | % input - parsed and scaled input points (struct of arrays) 165 | % n_size - number of points (integer) 166 | % output - struct with the generated output (struct of arrays) 167 | 168 | [y_1, y_2] = get_raw(input); 169 | sol.y_1 = y_1; 170 | sol.y_2 = y_2; 171 | 172 | end 173 | 174 | function [y_1, y_2] = get_raw(input) 175 | %GET_RAW Mathematical description of the function to be optimized. 176 | % [y_1, y_2] = GET_RAW(input) 177 | % input - parsed and scaled input points (struct of arrays) 178 | % y_1 - first output values (array) 179 | % y_2 - second output values (array) 180 | 181 | % assign 182 | x_1 = input.x_1; 183 | x_2 = input.x_2; 184 | x_3 = input.x_3; 185 | x_4 = input.x_4; 186 | 187 | % compute 188 | y_1 = x_1.^2+(x_2-2).^2+x_3; 189 | y_2 = 0.5*((x_1-2).^2+(x_2+1).^2)+2+x_4; 190 | 191 | end 192 | -------------------------------------------------------------------------------- /src/optim/get_pre_proc.m: -------------------------------------------------------------------------------- 1 | function [optim, n_var, n_init] = get_pre_proc(var_param) 2 | %GET_PRE_PROC Parse and scale the input variables, generates the initial points. 3 | % [optim, n_var, n_init] = GET_PRE_PROC(var_param) 4 | % var_param - struct with the variable description (struct) 5 | % data.n_max - maximum number of initial points for avoid out of memory crashes (integer) 6 | % data.fct_select - check if the generated iniitial points should be included (function handle) 7 | % idx = fct_select(input, n_size) 8 | % input - parsed and scaled input points (struct of arrays) 9 | % n_size - number of points (integer) 10 | % idx - indices to be selected (array of indices or array of logical) 11 | % data.var - cell of struct with the different variable description (cell of struct) 12 | % data.var{i}.type - type of the variable (string containing 'lin_float') 13 | % data.var{i}.name - name of the variable (string) 14 | % data.var{i} - description of a float variable with linear scale (type is 'float') 15 | % data.var{i}.scale - scaling of the variable (string) 16 | % 'lin' - no scaling is performed 17 | % 'log' - log10(x) scaling of the variable 18 | % 'exp' - 10^x scaling of the variable 19 | % 'square' - x^2 scaling of the variable 20 | % 'sqrt' - sqrt(x) scaling of the variable 21 | % data.var{i}.lb - lower boundary for the variable (float) 22 | % data.var{i}.ub - upper boundary for the variable (float) 23 | % data.var{i}.vec - vector with the values for the initial points (vector of floats) 24 | % data.var{i} - description of an integer variable (type is 'integer') 25 | % data.var{i}.set - integer with the set of possible values (array of integer) 26 | % data.var{i}.vec - integer with the initial combinations (array of integer) 27 | % data.var{i} - description of a constant (non-optimized) variable (type is 'scalar') 28 | % data.var{i}.v - value of the single constant variable (float) 29 | % optim - struct with the parsed variables (struct) 30 | % optim.lb - array containing the lower bounds of the variables (array) 31 | % optim.ub - array containing the upper bounds of the variables (array) 32 | % optim.int_con - array containing the index of the integer variables (array of indices) 33 | % optim.input - struct containing the constant (non-optimized) variables (struct of scalars) 34 | % optim.x0 - matrix containing the scaled initial points (matrix) 35 | % optim.fct_input - function creating the input struct from the scaled variables (function handle) 36 | % [input, n_size] = fct_input(x) 37 | % x - input points to be evaluated (matrix) 38 | % input - parsed and scaled input points (struct of arrays) 39 | % n_size - number of points (integer) 40 | % n_var - number of input variables used for the optimization (integer) 41 | % n_init - number of initial points used by the algorithm (integer) 42 | % 43 | % This function performs the following tasks on the variables: 44 | % - Find the lower and upper bounds 45 | % - Find the integer variables 46 | % - Find the constant variables 47 | % - Spanning the initial points 48 | % - Filtering the valid initial points 49 | % - Scaling the variables: 50 | % - Scale the 'float' variables with 'lin', 'log', 'exp', 'square', or 'sqrt' 51 | % - Mapping integer variables from [x1, x1, ..., xn] to [1, 2, ..., n] 52 | % 53 | % See also GET_MULTI_OBJ_OPT, GET_SOLUTION. 54 | % 55 | % (c) 2019-2020, ETH Zurich, Power Electronic Systems Laboratory, T. Guillod 56 | 57 | % extract the provided data 58 | var = var_param.var; 59 | n_max = var_param.n_max; 60 | fct_select = var_param.fct_select; 61 | 62 | % init the output 63 | var_scale = {}; 64 | lb = []; 65 | int_con = []; 66 | ub = []; 67 | x0_cell = {}; 68 | var_cst = struct(); 69 | 70 | % parse the different variable 71 | for i=1:length(var) 72 | var_tmp = var{i}; 73 | 74 | switch var_tmp.type 75 | case 'scalar' 76 | % scalar variable should not be array, assign them to the input struct 77 | assert(length(var_tmp.v)==1, 'invalid length') 78 | var_cst.(var_tmp.name) = var_tmp.v; 79 | case 'integer' 80 | % check that the initial points respect the set 81 | assert(length(var_tmp.set)>1, 'invalid length') 82 | assert(all(ismember(var_tmp.vec, var_tmp.set)), 'invalid initial vector') 83 | 84 | % get the scaling function 85 | [fct_scale, fct_unscale] = get_scale('integer'); 86 | 87 | % mapping integer variables from [x1, x1, ..., xn] to [1, 2, ..., n] 88 | var_scale{end+1} = struct('name', var_tmp.name, 'fct_unscale', @(x) fct_unscale(var_tmp.set, x)); 89 | x0_cell{end+1} = fct_scale(var_tmp.set, var_tmp.vec); 90 | 91 | % flag the integer variable 92 | int_con(end+1) = length(var_scale); 93 | 94 | % set the bounds in the transformed coordinates 95 | lb(end+1) = min(fct_scale(var_tmp.set, var_tmp.set)); 96 | ub(end+1) = max(fct_scale(var_tmp.set, var_tmp.set)); 97 | case 'float' 98 | % check that the initial points respect the bounds 99 | assert(var_tmp.ub>=var_tmp.lb, 'invalid length') 100 | assert(all(var_tmp.vec>=var_tmp.lb)&&all(var_tmp.vec<=var_tmp.ub), 'invalid initial vector') 101 | 102 | % get the scaling function 103 | [fct_scale, fct_unscale] = get_scale(var_tmp.scale); 104 | 105 | % set the scaled variable 106 | var_scale{end+1} = struct('name', var_tmp.name, 'fct_unscale', fct_unscale); 107 | x0_cell{end+1} = fct_scale(var_tmp.vec); 108 | 109 | % set the bounds 110 | lb(end+1) = fct_scale(var_tmp.lb); 111 | ub(end+1) = fct_scale(var_tmp.ub); 112 | otherwise 113 | error('invalid type') 114 | end 115 | end 116 | 117 | % function creating the input struct from the scaled variables 118 | fct_input = @(x) get_input(x, var_cst, var_scale); 119 | 120 | % get the size of the variable 121 | [n_var, n_init] = get_size(x0_cell, n_max); 122 | 123 | % span all the combinations between the initial points and filter them 124 | x0 = get_x0(x0_cell, fct_input, fct_select); 125 | 126 | % assign the data 127 | optim.fct_input = fct_input; 128 | optim.lb = lb; 129 | optim.ub = ub; 130 | optim.int_con = int_con; 131 | optim.x0 = x0; 132 | 133 | end 134 | 135 | function [fct_scale, fct_unscale] = get_scale(scale) 136 | %GET_SCALE Get the scaling and unscaling function. 137 | % [fct_scale, fct_unscale] = GET_SCALE(scale) 138 | % scale - type of the scaling to be done (string) 139 | % fct_scale - function to scale the variable (function handle) 140 | % fct_unscale - function to unscale the variable (function handle) 141 | 142 | switch scale 143 | case 'integer' 144 | fct_scale = @(set, vec) find(ismember(set, vec)); 145 | fct_unscale = @(set, vec) set(vec); 146 | case 'lin' 147 | fct_scale = @(x) x; 148 | fct_unscale = @(x) x; 149 | case 'log' 150 | fct_scale = @(x) log10(x); 151 | fct_unscale = @(x) 10.^x; 152 | case 'exp' 153 | fct_scale = @(x) 10.^x; 154 | fct_unscale = @(x) log10(x); 155 | case 'square' 156 | fct_scale = @(x) x.^2; 157 | fct_unscale = @(x) sqrt(x); 158 | case 'sqrt' 159 | fct_scale = @(x) sqrt(x); 160 | fct_unscale = @(x) x.^2; 161 | otherwise 162 | error('invalid scale') 163 | end 164 | 165 | end 166 | 167 | function [input, n_size] = get_input(x, var_cst, var_scale) 168 | %GET_INPUT Get the input struct from the scaled variable matrix. 169 | % [input, n_size] = GET_INPUT(x, input, var_scale) 170 | % x - matrix containing the scaled points to be computed (matrix of float) 171 | % var_cst - struct containg the constant variables (struct of scalars) 172 | % var_scale - cell containing the function to unscale the variables (cell of struct) 173 | % input - parsed and scaled input points (struct of arrays) 174 | % n_size - number of points (integer) 175 | 176 | % get the number of points 177 | n_size = size(x, 1); 178 | 179 | % unscaled the variable 180 | for i=1:length(var_scale) 181 | % extract the data 182 | name = var_scale{i}.name; 183 | fct_unscale = var_scale{i}.fct_unscale; 184 | 185 | % select the variable and unscale 186 | x_tmp = x(:,i).'; 187 | sweep.(name) = fct_unscale(x_tmp); 188 | end 189 | 190 | % extend the constant variable to the chunk size 191 | var_cst = get_struct_size(var_cst, n_size); 192 | 193 | % merge the optimized and constant variables 194 | field = [fieldnames(var_cst) ; fieldnames(sweep)]; 195 | value = [struct2cell(var_cst) ; struct2cell(sweep)]; 196 | input = cell2struct(value, field); 197 | 198 | end 199 | 200 | function [n_var, n_init] = get_size(x0_cell, n_max) 201 | %GET_SIZE Get and check the number of initial points. 202 | % [n_var, n_init] = GET_SIZE(x0_cell, n_max) 203 | % x0_cell - initial points of the different variables (cell of float arrays) 204 | % n_max - maximum number of initial points for avoid out of memory crashes (integer) 205 | % n_var - number of input variables used for the optimization (integer) 206 | % n_init - number of initial points used by the algorithm (integer) 207 | 208 | % all the combinations between the initial points 209 | n_init = prod(cellfun(@length, x0_cell)); 210 | n_init = max(1, n_init); 211 | assert(n_init<=n_max, 'invalid length'); 212 | assert(n_init>0, 'invalid length'); 213 | 214 | % number of optimization variables 215 | n_var = length(x0_cell); 216 | assert(n_var>0, 'invalid length'); 217 | 218 | end 219 | 220 | function x0 = get_x0(x0_cell, fct_input, fct_select) 221 | %GET_X0 Span all the combinations between the initial points and filter them. 222 | % x0 = GET_X0(x0_cell) 223 | % x0_cell - initial points of the different variables (cell of float arrays) 224 | % fct_input - function creating the input struct from the scaled variables (function handle) 225 | % fct_select - check if the generated iniitial points should be included (function handle) 226 | % x0 - matrix containing the scaled initial points (matrix of float) 227 | 228 | % get all the combinations 229 | x0_tmp = cell(1,length(x0_cell)); 230 | [x0_tmp{:}] = ndgrid(x0_cell{:}); 231 | for i=1:length(x0_tmp) 232 | x0(:,i) = x0_tmp{i}(:); 233 | end 234 | 235 | % filter the combinations 236 | [input, n_init] = fct_input(x0); 237 | idx_select = fct_select(input, n_init); 238 | x0 = x0(idx_select, :); 239 | 240 | end --------------------------------------------------------------------------------