[AllStat,Cache]=RunEDA(PopSize,n,F,Card,cache,edaparams) RUNEDA: Calls an EDA defined by the operators and parameters given by the user. A number of predefined operators (e.g. learning and sampling algorithms) have been implemented. Different BN structure learning algorithms are used INPUTS PopSize: Population size n: Number of variables F: Name of the function that has as an argument a vector or NumbVar variables. For multivariate functions the output of F is a vector with the number_of_objectives values. cache: Is a vector that determines which structures of the EDA will be stored. cache(1) = 1 : The whole population at each generation k will be saved in Cache{1,k}; cache(2) = 1 : The selected population at each generation k will be saved in Cache{2,k}; cache(3) = 1 : The probability model at each generation k will be saved in Cache{3,k}; cache(4) = 1 : The evaluation of the Population at each generation k will be saved in Cache{4,k}; cache(5) = 1 : The evaluation of the Population at each generation k will be saved in Cache{4,k}; edaparams: Array where each row includes three columns: 1) the 'type' of EDA operator method, 2) the 'name' of the EDA operator method, which is a matlab program defined by the user or could be one of the given implementations(see below) and 3) the parameters used by the implementation of the method. e.g. edaparams{1}(1) = 'sampling_method'; edaparams{1}(2) = 'PLS'; edaparams{1}(3) = {1000}; edaparams{2}(1) = 'selection_method; edaparams{2}(2) = 'truncation_selection'; edaparams{2}(3) = {0.15}; edaparams can appear in any order and there are a number of default of default values for all the operators (see below) The following are the different types of operators, given implementations and parameters. They are displayed type_of_method(fixed parameters, user defined parameters (method_params)) seeding_pop_method(n,PopSize,Card,seeding_pop_params): seeding_pop_method keeps the name of the matlab program that implements the seeding procedure. seeding_pop_method = 'RandomInit'(default) corresponds to random initialization Current implementations include: 'seeding_unitation_constraint': Generates a population of binary vectors where all vectors have the same number of ones seeding_pop_params: Depends on seeding method defined by the user. For seeding_pop_method='seeding_unitation_constraint', seeding_pop_params{1} = Number of ones in each solution sampling_method(n,PopSize,model,SelPop,SelFunVal,Card,sampling_params): Sampling methods implemented: 'SampleBN': Samples a BN of discrete variables using probabilistic logic sampling (PLS) 'MOAGeneratePopulation': Samples a Markov network using Gibbs Sampling 'SampleFDA': Samples a population of individuals from a factorized model using PLS 'SampleGaussianUnivModel': Samples a univariate Gaussian model sampling_params: sampling_params{1} = NewPopSize: Number of sampled individuals. By default sambpling_params{1} = PopSize, but it may change according to the replacement strategy. Additional params might be required by each sampling algorithm repairing_method(Pop,Card,reparing_params): Implements a repairing procedure. The whole population is received and all or some of the individuals are repaired repairing_params: Those needed to implement the repairing procedure local_opt_method(Pop,FunVal,local_opt_params): Implements a given local optimization procedure. The whole population is received and all or some of the individuals are optimized. The algorithm outputs the optimized population, with the new fitness values and number of evaluations done in the local optimization. local_opt_params: Those needed to implement the repairing procedure replacement_method(Pop,SelPop,NewPop,FunVal,SelFunVal,NewPopFunVal,replacement_params) Allows the implementation of replacement method that creates a new population from a set of three other populations (Current Pop, Sampled Pop, and Selected Pop) Current implementation includes replacement_method = {'elitism','best_elitism','pop_agregation'} 'elitism' adds the k best individuals of the previous population to the current pop. 'best_elitism' joins the selected individuals with the sampled individuals to form the next population. in this case, it should be enforced that SampledPopSize = PopSize - SelPopSize 'pop_aggregation' joins the current population with the new and select the best PopSize individuals as the new population. replacement_method = 'none' for Pop = NewPop. replacement_params: Depends on implementation. For replacement_metho For 'elitism': replacement_params{1} = k: number of elistist solutions and replacement_params{2} = find_bestids_method: method that implements a criterion to select the best individuals from a population. This is an important user-defined method. Currently find_bestids_method = 'fitness_ordering' which take into account fitness ordering (see help 'fitness_ordering' for details. For 'pop_agregation': replacement_params{1} = find_bestids_method. selection_method(Pop,FunVal,selection_params): 'selection_method' name of the matlab program selection method. Current implementations include: 'truncation_selection' (default), 'prop_selection' and 'exp_selection' selection_params: depends on the user implemented selection method (e.g) selection_params{1} = T: Truncation parameter T \in (0,1) for truncation selection learning_method(k,n,Card,SelPop,SelFunVal,learning_params): 'LearnBN': Bayesian network learning algorithms (see Help of the method for learning parameters) 'LearnMOAModel': Markov network learning algorithms (see Help of the method for learning parameters) statistics_method(k,Pop,FunVal,time_operations,number_evaluations,AllStat ,statistics_params): Implements the computation of the statistics about the EDA behavior. The statistics are stored in AllStat which may be used later for displaying information. Currently implemented is the method: 'simple_pop_statistics' statistics_params: Use for passing information necessary in the computation of the statistics (see 'simple_pop_statistics' for an example) verbose_method(k,AllStat,verbose_params): Defines the program used to display information about the EDA during the evolution Currently implemented is 'simple_verbose' which prints a number of statistics (depending on verbose_params) about generation k of the EDA verbose_params: stop_cond_method(currentgen,currentPop,currentFunVal,stop_cond_params): Implements the stop conditions of the algorithm. By default, the algorithm stops when reaching a maximum number of generations (1000). This is stop_cond_method = 'max_gen'. Current implementations include stop_cond_method = 'maxgen_maxval' which stops either when a maximum number of iterations has been reached or give value of the function has been reached stop_cond_params{1} = 1000; NOTE: the parameters currentPop and currentFunValallow the implementation of stop cond. methods based on the homogeneity of the population stop_cond_params: Depend on the stop_cond_method. For stop_cond_method = {'max_gen','maxgen_maxval'} stop_cond_params{1} = CantGen: Maximum number of generations stop_cond_method = 'maxgen_maxval', stop_cond_params{2} = MaximumFunction: Maximum of the function that can be used as stop condition when it is known OUTPUTS AllStat: Array containing the statistics of the populations. It is updated by the method AllStat{k,1}= matrix of 7 rows and number_objectives columns. Each row shows information about max,mean,median,min, and variance values of the corresponding objective in the current population AllStat{k,2}= Stores the best individual AllStat{k,3}= Number of different individuals AllStat{k,4}= matrix of 5 rows and n columns. Each row shows information about max,mean,median,min, and variance values of the corresponding variable in the current population AllStat{k,5} = Vector with the number of evaluations in each generation AllStat{k,6} = Matrix with the time in seconds spent at the main EDA steps, each of the 8 column stores the times for the following steps {sampling,repairing, evaluation,local optimization, ,replacement, selection,learning and total (which consider the time by the previous 7 and other EDA operations number_evaluations(1:k): Cache: Last version 8/26/2008. Roberto Santana (roberto.santana@ehu.es)
0001 function[AllStat,Cache]=RunEDA(PopSize,n,F,Card,cache,edaparams) 0002 % [AllStat,Cache]=RunEDA(PopSize,n,F,Card,cache,edaparams) 0003 % RUNEDA: Calls an EDA defined by the operators and parameters given by the 0004 % user. A number of predefined operators (e.g. learning and sampling 0005 % algorithms) have been implemented. 0006 % Different BN structure learning algorithms are used 0007 % INPUTS 0008 % PopSize: Population size 0009 % n: Number of variables 0010 % F: Name of the function that has as an argument a vector or NumbVar 0011 % variables. For multivariate functions the output of F is a vector with 0012 % the number_of_objectives values. 0013 % cache: Is a vector that determines which structures of the EDA will be 0014 % stored. 0015 % cache(1) = 1 : The whole population at each generation k will be saved in Cache{1,k}; 0016 % cache(2) = 1 : The selected population at each generation k will be saved in Cache{2,k}; 0017 % cache(3) = 1 : The probability model at each generation k will be saved in Cache{3,k}; 0018 % cache(4) = 1 : The evaluation of the Population at each generation k will be saved in Cache{4,k}; 0019 % cache(5) = 1 : The evaluation of the Population at each generation k will be saved in Cache{4,k}; 0020 % edaparams: Array where each row includes three columns: 1) the 'type' of 0021 % EDA operator method, 2) the 'name' of the EDA operator method, which is a 0022 % matlab program defined by the user or could be one of the given implementations(see below) and 3) the 0023 % parameters used by the implementation of the method. 0024 % e.g. edaparams{1}(1) = 'sampling_method'; edaparams{1}(2) = 'PLS'; edaparams{1}(3) = {1000}; 0025 % edaparams{2}(1) = 'selection_method; edaparams{2}(2) = 'truncation_selection'; edaparams{2}(3) = {0.15}; 0026 % edaparams can appear in any order and there are a number of default of default values for all the operators (see below) 0027 % 0028 % The following are the different types of operators, given implementations and parameters. They are displayed 0029 % 0030 % type_of_method(fixed parameters, user defined parameters (method_params)) 0031 % 0032 % seeding_pop_method(n,PopSize,Card,seeding_pop_params): 0033 % seeding_pop_method keeps the name of the matlab program that implements the seeding 0034 % procedure. seeding_pop_method = 'RandomInit'(default) corresponds to random initialization 0035 % Current implementations include: 0036 % 'seeding_unitation_constraint': Generates a population of binary vectors where all vectors have the same number of ones 0037 % seeding_pop_params: Depends on seeding method defined by the user. For seeding_pop_method='seeding_unitation_constraint', seeding_pop_params{1} 0038 % = Number of ones in each solution 0039 % sampling_method(n,PopSize,model,SelPop,SelFunVal,Card,sampling_params): 0040 % Sampling methods implemented: 0041 % 'SampleBN': Samples a BN of discrete variables using probabilistic logic sampling (PLS) 0042 % 'MOAGeneratePopulation': Samples a Markov network using Gibbs Sampling 0043 % 'SampleFDA': Samples a population of individuals from a factorized model using PLS 0044 % 'SampleGaussianUnivModel': Samples a univariate Gaussian model 0045 % sampling_params: sampling_params{1} = NewPopSize: Number of 0046 % sampled individuals. By default sambpling_params{1} = PopSize, but it 0047 % may change according to the replacement strategy. 0048 % Additional params might be required by each sampling algorithm 0049 % repairing_method(Pop,Card,reparing_params): 0050 % Implements a repairing procedure. The whole population is received and all or some of the 0051 % individuals are repaired 0052 % repairing_params: Those needed to implement the repairing procedure 0053 % local_opt_method(Pop,FunVal,local_opt_params): 0054 % Implements a given local optimization procedure. The whole population is received and all or some of the 0055 % individuals are optimized. The algorithm outputs 0056 % the optimized population, with the new fitness values and number of evaluations done in the local 0057 % optimization. 0058 % local_opt_params: Those needed to implement the repairing procedure 0059 % replacement_method(Pop,SelPop,NewPop,FunVal,SelFunVal,NewPopFunVal,replacement_params) 0060 % Allows the implementation of replacement method that creates a new population from a set of three other 0061 % populations (Current Pop, Sampled Pop, and Selected Pop) 0062 % Current implementation includes replacement_method = {'elitism','best_elitism','pop_agregation'} 0063 % 'elitism' adds the k best individuals of the previous population to the current pop. 0064 % 'best_elitism' joins the selected individuals with the sampled individuals to form the next population. 0065 % in this case, it should be enforced that SampledPopSize = PopSize - SelPopSize 0066 % 'pop_aggregation' joins the current population with the new and select the best PopSize 0067 % individuals as the new population. 0068 % replacement_method = 'none' for Pop = NewPop. 0069 % replacement_params: Depends on implementation. For replacement_metho 0070 % For 'elitism': replacement_params{1} = k: number of elistist solutions 0071 % and replacement_params{2} = find_bestids_method: method that implements a criterion to select the 0072 % best individuals from a population. This is an important user-defined method. Currently 0073 % find_bestids_method = 'fitness_ordering' which take into account fitness ordering (see help 0074 % 'fitness_ordering' for details. 0075 % For 'pop_agregation': replacement_params{1} = find_bestids_method. 0076 % selection_method(Pop,FunVal,selection_params): 'selection_method' name of the matlab program selection method. Current implementations include: 0077 % 'truncation_selection' (default), 'prop_selection' and 'exp_selection' 0078 % selection_params: depends on the user implemented selection method 0079 % (e.g) selection_params{1} = T: Truncation parameter T \in (0,1) for truncation selection 0080 % learning_method(k,n,Card,SelPop,SelFunVal,learning_params): 0081 % 'LearnBN': Bayesian network learning algorithms (see Help of the method for learning parameters) 0082 % 'LearnMOAModel': Markov network learning algorithms (see Help of the method for learning parameters) 0083 % 0084 % statistics_method(k,Pop,FunVal,time_operations,number_evaluations,AllStat ,statistics_params): 0085 % Implements the computation of the statistics about the EDA behavior. 0086 % The statistics are stored in AllStat which may be used later for displaying information. 0087 % Currently implemented is the method: 'simple_pop_statistics' 0088 % statistics_params: Use for passing information necessary in the 0089 % computation of the statistics (see 'simple_pop_statistics' for an example) 0090 % verbose_method(k,AllStat,verbose_params): 0091 % Defines the program used to display information about the EDA during the evolution 0092 % Currently implemented is 'simple_verbose' which prints a number of statistics 0093 % (depending on verbose_params) about generation k of the EDA 0094 % verbose_params: 0095 % stop_cond_method(currentgen,currentPop,currentFunVal,stop_cond_params): 0096 % Implements the stop conditions of the algorithm. By default, the algorithm 0097 % stops when reaching a maximum number of generations (1000). This is 0098 % stop_cond_method = 'max_gen'. Current implementations include stop_cond_method = 0099 % 'maxgen_maxval' which stops either when a maximum number of iterations has been reached or give 0100 % value of the function has been reached stop_cond_params{1} = 1000; 0101 % NOTE: the parameters currentPop and currentFunValallow the implementation of stop cond. methods 0102 % based on the homogeneity of the population 0103 % stop_cond_params: Depend on the stop_cond_method. For 0104 % stop_cond_method = {'max_gen','maxgen_maxval'} stop_cond_params{1} = CantGen: Maximum number of generations 0105 % stop_cond_method = 'maxgen_maxval', stop_cond_params{2} = MaximumFunction: Maximum of the function that can be used as stop 0106 % condition when it is known 0107 % OUTPUTS 0108 % AllStat: Array containing the statistics of the populations. 0109 % It is updated by the method 0110 % AllStat{k,1}= matrix of 7 rows and number_objectives 0111 % columns. Each row shows information about 0112 % max,mean,median,min, and variance values of the 0113 % corresponding objective in the current population 0114 % AllStat{k,2}= Stores the best individual 0115 % AllStat{k,3}= Number of different individuals 0116 % AllStat{k,4}= matrix of 5 rows and n 0117 % columns. Each row shows information about 0118 % max,mean,median,min, and variance values of the 0119 % corresponding variable in the current population 0120 % AllStat{k,5} = Vector with the number of evaluations in each generation 0121 % AllStat{k,6} = Matrix with the time in seconds spent at the main 0122 % EDA steps, each of the 8 column stores the times for the 0123 % following steps {sampling,repairing, evaluation,local optimization, ,replacement, selection,learning and 0124 % total (which consider the time by the previous 7 and 0125 % other EDA operations 0126 % 0127 % number_evaluations(1:k): 0128 % Cache: 0129 % 0130 % Last version 8/26/2008. Roberto Santana (roberto.santana@ehu.es) 0131 0132 0133 % Default operators and parameters 0134 0135 seeding_pop_method = 'RandomInit'; 0136 seeding_pop_params = []; 0137 sampling_method = 'SampleBN'; 0138 sampling_params{1}(1) = {PopSize}; 0139 repairing_method = 'none'; 0140 repairing_params = []; 0141 local_opt_method = 'none'; 0142 local_opt_params = []; 0143 replacement_method = 'best_elitism'; 0144 replacement_params{1,1} = 'fitness_ordering'; 0145 selection_method = 'truncation_selection'; 0146 selection_params{1}(1) = {0.5}; 0147 selection_params{1}(2)= {'fitness_ordering'}; 0148 learning_method = 'LearnBN'; 0149 learning_params{1,1} = {'tree'}; 0150 learning_params{1}(2) = {10}; 0151 learning_params{1}(3) = {0.05}; 0152 learning_params{1}(4) = {'pearson'}; 0153 learning_params{1}(5) = {'bic'}; 0154 learning_params{1}(6) = {'no'}; 0155 statistics_method = 'simple_pop_statistics'; 0156 statistics_params{1}(1)= {'fitness_ordering'}; 0157 verbose_method = 'simple_verbose'; 0158 verbose_params{1,1} = []; 0159 stop_cond_method = 'max_gen'; 0160 stop_cond_params{1}(1) = {50}; % Number of generations 0161 Cache = {}; 0162 0163 nparams = size(edaparams,2); 0164 0165 for i = 1:nparams 0166 auxstr = char(cellstr(edaparams{i}(1))); 0167 auxstr2 = char(cellstr(edaparams{i}(2))); 0168 0169 0170 switch auxstr 0171 case 'seeding_pop_method', seeding_pop_method = auxstr2;, seeding_pop_params = edaparams{i}(3); 0172 case 'sampling_method', sampling_method = auxstr2;, sampling_params = edaparams{i}(3); 0173 case 'repairing_method', repairing_method = auxstr2;, repairing_params = edaparams{i}(3); 0174 case 'local_opt_method', local_opt_method = auxstr2;, local_opt_params = edaparams{i}(3); 0175 case 'replacement_method', replacement_method = auxstr2;, replacement_params = edaparams{i}(3); 0176 case 'selection_method', selection_method = auxstr2;, selection_params = edaparams{i}(3); 0177 case 'learning_method', learning_method = auxstr2;, learning_params = edaparams{i}(3); 0178 case 'statistics_method', statistics_method = auxstr2;, statistics_params = edaparams{i}(3); 0179 case 'verbose_method', verbose_method = auxstr2;, verbose_params = edaparams{i}(3); 0180 case 'stop_cond_method', stop_cond_method = auxstr2;, stop_cond_params = edaparams{i}(3); 0181 end; 0182 end; 0183 0184 auxedaparams{1,:} = {PopSize,n,F,Card}; 0185 auxedaparams{2,:} = {'seeding_pop_method', seeding_pop_method, seeding_pop_params}; 0186 auxedaparams{3,:} = {'sampling_method', sampling_method, sampling_params}; 0187 auxedaparams{4,:} = { 'repairing_method', repairing_method , repairing_params }; 0188 auxedaparams{5,:} = { 'local_opt_method', local_opt_method , local_opt_params }; 0189 auxedaparams{6,:} = { 'replacement_method', replacement_method , replacement_params }; 0190 auxedaparams{7,:} = { 'selection_method', selection_method , selection_params}; 0191 auxedaparams{8,:} = { 'learning_method', learning_method , learning_params}; 0192 auxedaparams{9,:} = { 'statistics_method', statistics_method , statistics_params}; 0193 auxedaparams{10,:} = { 'verbose_method', verbose_method, verbose_params }; 0194 auxedaparams{11,:} = { 'stop_cond_method', stop_cond_method , stop_cond_params }; 0195 0196 0197 continue_evolution = 1; 0198 k = 1; 0199 AllStat = {}; 0200 number_objectives = size(F,1); 0201 NewPopSize = cell2num(sampling_params{1}(1)); 0202 CantGen = cell2num(stop_cond_params{1}(1)); 0203 0204 previous_t = cputime; 0205 0206 while(continue_evolution==1) 0207 0208 t = cputime; 0209 if(k==1) 0210 % Initialization of the population . 0211 % Random by default. Alternatively, seeding procedure seeding_pop_method. 0212 Pop = eval([seeding_pop_method,'(n,PopSize,Card,seeding_pop_params)']); 0213 else 0214 % The new population is sampled from the learned model 0215 NewPop = eval([sampling_method,'(n,model,Card,SelPop,SelFunVal,sampling_params)']); 0216 end 0217 0218 time_operations(k,1) = cputime-t; % Time spent in sampling 0219 0220 0221 t = cputime; 0222 0223 if(~strcmp(repairing_method,'none') == 1) 0224 if(k==1) 0225 [Pop] = eval([repairing_method,'(Pop,Card,repairing_params)']); % Repairing method is applied 0226 else 0227 [NewPop] = eval([repairing_method,'(NewPop,Card,repairing_params)']); % Repairing method is applied 0228 end 0229 end 0230 0231 time_operations(k,2) = cputime-t; % Time spent in repairing 0232 0233 0234 t = cputime; 0235 % The sampled population is evaluated 0236 0237 if k==1 0238 for i=1:PopSize, 0239 FunVal(i,:) = feval(F,Pop(i,:)); 0240 end 0241 number_evaluations(k) = PopSize ; 0242 % FunVal' 0243 else 0244 for i=1:NewPopSize, 0245 NewPopFunVal(i,:) = feval(F,NewPop(i,:)); 0246 end 0247 number_evaluations(k) = number_evaluations(k-1) + NewPopSize ; 0248 % NewPopFunVal' 0249 end 0250 0251 time_operations(k,3) = cputime-t; % Time spent in evaluation 0252 0253 0254 t = cputime; 0255 0256 if(~strcmp(local_opt_method,'none') == 1) % Local optimization method is applied 0257 if k==1 0258 [Pop,FunVal,NumbEvals] = eval([local_opt_method,'(k,Pop,FunVal,local_opt_params)']); 0259 number_evaluations(k) = number_evaluations(k) + NumbEvals; 0260 %aux = FunVal' 0261 else 0262 [NewPop,NewPopFunVal,NumbEvals] = eval([local_opt_method,'(k,NewPop,NewPopFunVal,local_opt_params)']); 0263 number_evaluations(k) = number_evaluations(k) + NumbEvals; 0264 % aux = NewPopFunVal' 0265 end 0266 end 0267 0268 time_operations(k,4) = cputime-t; % Time spent in local optimization 0269 0270 0271 t = cputime; 0272 if k>1 % In the first generation, the generated population is just the current population 0273 % Replacement algorithm (e.g. elitism). The new population is formed using the previous population, the 0274 % selected population and the sampled population. 0275 if(strcmp(replacement_method,'none') == 1) 0276 Pop = NewPop; % By default, the new population in the one just generated 0277 FunVal = NewPopFunVal; 0278 else % Alternatively another 0279 [Pop,FunVal] = eval([replacement_method,'(Pop,SelPop,NewPop,FunVal,SelFunVal,NewPopFunVal,replacement_params)']); 0280 0281 end 0282 end 0283 0284 0285 0286 if (cache(1)==1) 0287 Cache{1,k} = Pop; 0288 end 0289 if (cache(4)==1) 0290 Cache{4,k} = FunVal; 0291 end 0292 0293 time_operations(k,5) = cputime-t; % Time spent in replacement 0294 0295 0296 t = cputime; 0297 0298 % Selection is applied 0299 [SelPop,SelFunVal] = eval([selection_method,'(Pop,FunVal,selection_params)']); 0300 if (cache(2)==1) 0301 Cache{2,k} = SelPop; 0302 end 0303 if (cache(5)==1) 0304 Cache{5,k} = SelFunVal; 0305 end 0306 0307 time_operations(k,6) = cputime-t; % Time spent in selection 0308 0309 0310 t = cputime; 0311 % The model is learned using one of the predefined learning algorithms 0312 0313 [model] = eval([learning_method,'(k,n,Card,SelPop,SelFunVal,learning_params)']); 0314 if (cache(3)==1) 0315 Cache{3,k} = model; 0316 end 0317 0318 time_operations(k,7) = cputime-t; % Time spent in learning 0319 0320 0321 0322 if(strcmp(stop_cond_method,'max_gen') == 1) % Default stop condition: maximum number of generations 0323 continue_evolution = (k<CantGen); 0324 else % Alternatively, a given stop condition method that uses current 0325 % information about the EDA evolution plus external inf. (e.g. 0326 % known maximum value) 0327 continue_evolution = eval([stop_cond_method,'(k,Pop,FunVal,stop_cond_params)']); 0328 end 0329 0330 0331 time_operations(k,8) = cputime - previous_t; % Time spent in the whole generation 0332 previous_t = cputime; 0333 % Statistics are computed 0334 [AllStat] = eval([statistics_method,'(k,Pop,FunVal,time_operations,number_evaluations,AllStat,statistics_params)']); 0335 0336 0337 if(strcmp(verbose_method,'none') ~= 1) % Statistics information about the run is printed 0338 eval([verbose_method,'(k,AllStat,verbose_params,auxedaparams)']); 0339 end 0340 0341 k=k+1; 0342 end 0343 0344 0345 return 0346 0347 0348 0349