-
Notifications
You must be signed in to change notification settings - Fork 0
/
GeneticAlgorithmCode.m
2290 lines (1939 loc) · 105 KB
/
GeneticAlgorithmCode.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
classdef GeneticAlgorithmCode < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
GeneticAlgorithmUIFigure matlab.ui.Figure
GeneticAlgorithmLabel matlab.ui.control.Label
GenerateButton matlab.ui.control.Button
PopulationSizeLabel matlab.ui.control.Label
PopulationSizeEditField matlab.ui.control.NumericEditField
StringsPerChromosomeLabel matlab.ui.control.Label
StringsPerChromosomeEditField matlab.ui.control.NumericEditField
BitsPerStringEditFieldLabel matlab.ui.control.Label
BitsPerStringEditField matlab.ui.control.NumericEditField
FunctionEditFieldLabel matlab.ui.control.Label
FunctionEditField matlab.ui.control.EditField
TypeofValuesDropDownLabel matlab.ui.control.Label
TypeofValuesDropDown matlab.ui.control.DropDown
MinMaxLabel matlab.ui.control.Label
MinMaxDropDown matlab.ui.control.DropDown
EvaluationLabel matlab.ui.control.Label
PopulationGenerationLabel matlab.ui.control.Label
SetinitialPopulationButton matlab.ui.control.Button
DecimalPlacesEditFieldLabel matlab.ui.control.Label
DecimalPlacesEditField matlab.ui.control.NumericEditField
CrossOverLabel matlab.ui.control.Label
ButtonGroup matlab.ui.container.ButtonGroup
PointButton matlab.ui.control.RadioButton
PointsButton matlab.ui.control.RadioButton
SetRangesButton matlab.ui.control.Button
GenerationLabel matlab.ui.control.Label
StopatGenerationLabel matlab.ui.control.Label
StopatGenerationEditField matlab.ui.control.NumericEditField
SelectionLabel matlab.ui.control.Label
ButtonGroup_2 matlab.ui.container.ButtonGroup
RolletteWheelButton matlab.ui.control.RadioButton
ElitismButton matlab.ui.control.RadioButton
GeneralProbabilitiesLabel matlab.ui.control.Label
CrossOverProbabilityEditFieldLabel matlab.ui.control.Label
CrossOverProbabilityEditField matlab.ui.control.NumericEditField
MutationProbabilityEditFieldLabel matlab.ui.control.Label
MutationProbabilityEditField matlab.ui.control.NumericEditField
end
properties (Access = private)
Err = [0 1 1 1]; % Variable for tracking errors
ChromNumErr = 1; % Index of Err corresponding to no of chromosomes
% error
RngErr = 2; % Index of Err corresponding to Range error
PopErr = 3; % Index of Err corresponding to Population error
FuncErr = 4; % Index of Err corresponding to function error
Rng % Ranges for strings
LastRng % Last valid user input for ranges
Pop = ""; % Population
LastPop = ""; % Last valid population
% Initial Generation
GenZero = struct('initPop',"",'denVal',[],'decVal',[],'fx',[],...
'fit',[],'cumFit',[],'selChroms',[],'bestTillNow',"",'bestFitTillNow',[],...
'finalPop',[]);
% Other Generations
Gen = struct('initPop',"",'crossPairs',[],'crossProbs',[],...
'crossPoints',[],'doCross',[],'crossedPop',[],...
'mutPairs',[],'mutProbs',[],'mutPoints',[],...
'doMutation',[],'mutatedPop',[],'denVal',[],...
'decVal',[],'fx',[],'fit',[],'cumFit',[],...
'selChroms',[],'bestTillNow',"",...
'bestFitTillNow',[],'finalPop',[]);
end
methods (Access = private)
function cellRng = RngCell(app)
%This function stores each set of ranges in app.Rng as a
%string in the output cell array (cellRng)
cellRng = cell(size(app.Rng,1),1);
for row = 1:length(cellRng)
cellRng{row} = num2str(app.Rng(row,:));
end
end
function ResetRngVal(app,val,input)
% This function sets the values of the ranges as the
% default value if val is 1 or to the last valid values
% if val is 2
% Get the number of strings per chromosomes
strNum = app.StringsPerChromosomeEditField.Value;
% Get the number of bits per chromosome
bits = app.BitsPerStringEditField.Value;
% Get the number of decimal places
decPl = app.DecimalPlacesEditField.Value;
if val == 1
if (app.TypeofValuesDropDown.Value == 1)
app.Rng = repmat([0 10],strNum,1);
else
app.Rng = repmat([0 (10^bits-1)*10^-decPl],strNum,1);
end
elseif val == 2
if size(app.LastRng,1) < strNum
if (app.TypeofValuesDropDown.Value == 1)
app.Rng = [app.LastRng; repmat([0 10],...
strNum-size(app.LastRng,1),1)];
else
app.Rng = [app.LastRng; repmat([0 (10^bits-1)*10^-decPl],...
strNum-size(app.LastRng,1),1)];
end
elseif size(app.LastRng,1) > strNum
app.Rng = app.LastRng(1:strNum,:);
else
app.Rng = app.LastRng;
end
end
% Save the ranges in a cell array
cellRng = app.RngCell();
% Output the ranges in the GUI for ranges and make
% background white
input.Value = cellRng;
input.BackgroundColor = '#fff';
end
function checkRngVal(app,uf,input)
% Get the number of strings per chromosomes
strNum = app.StringsPerChromosomeEditField.Value;
% Get the number of bits per strings
bits = app.BitsPerStringEditField.Value;
% get the number of decimal places
decPl = app.DecimalPlacesEditField.Value;
% If input is empty or number of rows is not equal to
% number of strings raise error otherwise continue to else
if string(input.Value) == ""
uialert(uf,'There are no values. There should be '+...
string(strNum)+' sets of ranges','Error')
input.BackgroundColor = '#EDB120';
elseif size(input.Value,1) ~= strNum
uialert(uf,'There are '+string(size(input.Value,1))+...
' sets of values. There should be '+string(strNum)+...
' sets of ranges','Error')
input.BackgroundColor = '#EDB120';
else
% Empty 2-column cell array with rows equal to length
% of input values
cellAScan = cell(size(input.Value,1),2);
% expr is a regular expression to check if each line of
% input contains exactly two numbers separated by one
% or more space characters
expr = "([-]*[\d]+\.[\d]*|(?:[-]*[\d]*)?[.]?[\d]+)[ ]+"+...
"([-]*[\d]+\.[\d]*|(?:[-]*[\d]*)?[.]?[\d]+)";
% Error check each line of input. If any error track
% with valErr
for i = 1:size(input.Value,1)
% Remove leading and trailing spaces then check if current line matches expr
[start,last] = regexp(strip(input.Value{i}),expr,'once');
if isempty(start) && isempty(last)
% current line does not match expr
alertmsg{2,1} = 'min and max should be integers separated by space';
alertmsg{1,1} = 'Input format: min max';
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
elseif (start(1) == 1 && last(end) == length(strip(input.Value{i})))
% Current line matches expr exactly
% Capture the two numbers into respective columns in cellAScan
cellAScan(i,:) = textscan(input.Value{i},'%f %f');
if ~(cellAScan{i,1} <= cellAScan{i,2})
% First number (min) is greater than the second number (max)
alertmsg = 'Each min should not be greater than the respective max';
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
elseif (app.TypeofValuesDropDown.Value == 2 && cellAScan{i,1}<0)
% Type is real and first Number is lesser than zero
format long
alertmsg = 'Each min should not be lesser than zero';
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
elseif (app.TypeofValuesDropDown.Value == 2 ...
&& cellAScan{i,2}>(10^bits)*10^-decPl)
% Type is real and the second number is higher than
% the maximum possible value. the maximum posibble
% value is 10 raised to the power of the number of
% bits minus one then shift decimal places forward
% by the specified decimal places
% Every value in the population is to the decimal
% places specified from onset
format long
alertmsg = "Each max should be lesser than "+...
string((10^bits-1)*10^-decPl);
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
else % first number (min) is lesser than or equal to the second number (max)
valErr = 0;
input.BackgroundColor = '#fff';
end
else % current line matches expr partly
alertmsg{2,1} = 'min and max should be two integers separated by space';
alertmsg{1,1} = 'Input format: min max';
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
end
end
if ~valErr % if no error occurs
% update the values of the ranges (app.Rng)
app.Rng = cell2mat(cellAScan);
% change the button background to white
app.SetRangesButton.BackgroundColor = '#fff';
% discard Range Error if raised
app.Err(app.RngErr) = 0;
% change the input background to white
input.BackgroundColor = '#fff';
% If current value for ranges is not the default values
% update app.LastRng to the current values of ranges
if ~isequal(app.Rng,repmat([0 10],strNum,1))
app.LastRng = app.Rng;
end
%Check for any errors if any disable Generate button
app.checkErr();
% Remove the * in the button text
app.SetRangesButton.Text = "Set Ranges";
% Close figure for setting ranges
close(uf);
end
end
end
function rngUfDeleteFcn(app)
% This function shows the base GUI when the GUI for ranges
% is being deleted
% Using modal for this second uifigure should be better but
% modal is not available in MATLAB R2019b. I want to update
% this part when I get a later version of MATLAB
app.GeneticAlgorithmUIFigure.Visible = 'on';
end
function rngUfCloseFcn(app,uf)
% This function shows the base GUI when the GUI for ranges
% has been deleted
% Using modal for this second uifigure should be better but
% modal is not available in MATLAB R2019b. I want to update
% this part when I get a later version of MATLAB
delete(uf);
app.GeneticAlgorithmUIFigure.Visible = 'on';
end
function cellPop = PopLines(app)
%This function stores each row of Populaion in app.Pop as
% a string in the output cell array (cellPop) if app.Pop is not
% empty
if app.Pop ~= ""
cellPop = strings(size(app.Pop,1),1);
for i = 1:length(cellPop)
cellPop(i) = strjoin(app.Pop(i,:));
end
else
cellPop = '';
end
end
function ResetPopVal(app,val,input)
% This function sets the values of the Population as
% random values if val is 1 or to the last valid values
% if val is 2
% Get the dropdown value 1 (binary) or 2 (real)
type = app.TypeofValuesDropDown.Value;
% Get the number of chromosomes
chromNum = app.PopulationSizeEditField.Value;
% Get number of strings
strNum = app.StringsPerChromosomeEditField.Value;
% Get the number of bits per string
bitNum = app.BitsPerStringEditField.Value;
% get the number of decimal places
decPl = app.DecimalPlacesEditField.Value;
if val == 1
% Set random population according to the type (binary or real)
if type == 1
% Type is binary
% Generate random numbers where the maximum value is
% the maximum value a binary number with bitNum digits
% can have and the lowest possible value is zero
randInts = randi([0 2^bitNum-1],chromNum,strNum);
else
% Type is real
randInts = zeros(chromNum,strNum);
for i = 1:strNum
% Check each range if the value is higher than the
% highest possible value make the up limit the highest
% possible value else make the up limit equal to the
% range
if (10^bitNum-1) <= round(app.Rng(i,2)*10^decPl)
upLim = 10^bitNum-1;
else
upLim = round(app.Rng(i,2)*10^decPl);
end
% Make the down limit the min of the ranges
downLim = round(app.Rng(i,1)*10^decPl);
% Generate random numbers for each column (string)
% between uplim and downlim for such column
randInts(:,i) = randi([downLim upLim],chromNum,1);
end
end
% Empty Pop having the required size
app.Pop = strings(chromNum,strNum);
% Fill each element in the population with binary values of
% the randomly generated numbers (ranInts) each filled
% element in the population has number of digits equal to
% the number of bits specified
if type == 1
for i=1:strNum
app.Pop(:,i) = string(dec2bin(randInts(:,i),bitNum));
end
elseif type == 2
for i=1:chromNum
for j=1:strNum
app.Pop(i,j) = sprintf("%0"+...
string(bitNum)+"d",randInts(i,j));
end
end
end
elseif val ==2
% Set last valid population if it exists
% If no last valid values raise error else make
% Population equal to last valid values
if app.LastPop == ""
alertmsg{2,1} = 'You can use random population instead';
alertmsg{1,1} = 'No population has been set yet';
uialert(uf,alertmsg,'Error');
else
app.Pop = app.LastPop;
end
end
% Save Population in a cell array
cellPopOut = app.PopLines();
% Output the Population in the GUI for Population
input.Value = cellPopOut;
% Make the input background white
input.BackgroundColor = '#fff';
end
function set(app,uf,input)
% Get the dropdown value 1 (binary) or 2 (real)
type = app.TypeofValuesDropDown.Value;
% Get the number of chromosomes
chromNum = app.PopulationSizeEditField.Value;
% Get number of strings
strNum = app.StringsPerChromosomeEditField.Value;
% Get the number of bits per string
bitNum = app.BitsPerStringEditField.Value;
% Get the number of decimalplaces
decPl = app.DecimalPlacesEditField.Value;
% If input is empty or number of rows is not equal to
% number of strings raise error otherwise continue to else
if string(input.Value) == ""
uialert(uf,'There are no values. There should be '+...
string(chromNum)+' chromosome populations','Error')
input.BackgroundColor = '#EDB120';
elseif size(input.Value,1) ~= chromNum
uialert(uf,'There are '+string(size(input.Value,1))+...
' values. There should be '+string(chromNum)+...
' chromosome Populations','Error')
input.BackgroundColor = '#EDB120';
else
% Empty 2-column cell array with rows equal to length
% of input values
cellPopScan = cell(size(input.Value,1),strNum);
% Set the type and number of digits required according
% to type (binary or real) and number of bits
if type == 1
digits = "[0-1]{"+string(bitNum)+"}";
labelend = ' of 1s and 0s';
elseif type == 2
digits = "\d{"+string(bitNum)+"}";
labelend = '';
end
% expr is a regular expression for checking the inputs
expr = strjoin(repmat(digits,1,strNum),'[ ]+');
% Error check each line of input. If any error track
% with valErr
for i = 1:size(input.Value,1)
% Remove leading and trailing spaces then check if
% current line matches expr
[start,last] = regexp(strip(input.Value{i}),expr,'once');
if isempty(start) && isempty(last)
% current line does not match expr
alertmsg = sprintf("Format: Input %d %d-digit numbers"+...
"%s\nfor each chromosome (row)",strNum,bitNum,labelend);
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
elseif (start(1) == 1 && last(end) == length(strip(input.Value{i})))
% current line matches expr exactly
scanformat = strjoin(repmat("%s",1,strNum));
cellPopScan(i,:) = textscan(input.Value{i},scanformat);
% If type is one do not check if the values are
% within the specified ranges else (type is real)
% check
if type == 1
valErr = 0;
input.BackgroundColor = '#fff';
elseif type == 2
for j = 1:size(cellPopScan(i,:),2)
if str2double(cellPopScan{i,j})*10^-decPl < app.Rng(j,1)
% An element in the population is lesser
% than the min range for the string it
% belongs
alertmsg = sprintf("Each value should be more than %d",...
app.Rng(j,1)*10^-decPl);
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
elseif str2double(cellPopScan{i,j})*10^-decPl > app.Rng(j,2)
% An element in the population is more than
% the max range for the string it belongs
alertmsg = sprintf("Each value should be lesser than %d",...
app.Rng(j,2)*10^-decPl);
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
else
valErr = 0;
input.BackgroundColor = '#fff';
end
end
end
% If error was raised stop checking the inputs
if valErr
break
end
else
% current line matches expr partly
alertmsg = sprintf("Format: Input %d %d-digit numbers"+...
"%s\nfor each chromosome (row)",strNum,bitNum,labelend);
uialert(uf,alertmsg,'Error')
valErr = 1;
input.BackgroundColor = '#EDB120';
break
end
end
if ~valErr
% if no error occurs
% Update the values of the Population (app.Pop)
app.Pop = strings(chromNum,strNum);
for i = 1:size(cellPopScan,1)
for j = 1:size(cellPopScan,2)
app.Pop(i,j) = string(cellPopScan{i,j});
end
end
% Set input background to white
input.BackgroundColor = '#fff';
% Update Last Valid Population (app.LastPop)
app.LastPop = app.Pop;
% Set button background to white
app.SetinitialPopulationButton.BackgroundColor = '#fff';
% discard Range Error if raised
app.Err(app.PopErr) = 0;
%Check for any errors if any disable Generate button
app.checkErr();
% Remove the * in the button text
app.SetinitialPopulationButton.Text = "Set Initial Population";
% Close the figure
close(uf)
end
end
end
function popUfDeleteFcn(app)
% This function shows the base GUI when the GUI for ranges
% is being deleted
% Using modal for this second uifigure should be better but
% modal is not available in MATLAB R2019b. I want to update
% this part when I get a later version of MATLAB
app.GeneticAlgorithmUIFigure.Visible = 'on';
end
function popUfCloseFcn(app,uf)
% This function shows the base GUI when the GUI for ranges
% has been deleted
% Using modal for this second uifigure should be better but
% modal is not available in MATLAB R2019b. I want to update
% this part when I get a later version of MATLAB
delete(uf);
app.GeneticAlgorithmUIFigure.Visible = 'on';
end
function RngPopErr(app)
% Raise error for Range
app.SetRangesButton.BackgroundColor = '#EDB120';
app.Err(app.RngErr) = 1;
% Raise error for Population
app.SetinitialPopulationButton.BackgroundColor = '#EDB120';
app.Err(app.PopErr) = 1;
end
function checkErr(app)
% Check for errors
if any(app.Err)
% Disable Generate Button
app.GenerateButton.Enable = 0;
else
% Enable Generate Button
app.GenerateButton.Enable = 1;
end
end
function CurGen = cross(app,GenNo)
% This function does the crossover anywhere required
% Get the population size
popSize = app.PopulationSizeEditField.Value;
% Get the number of strings
strNo = app.StringsPerChromosomeEditField.Value;
% Get the number of bits
bits = app.BitsPerStringEditField.Value;
% Get the generation to work on according to the number
% specified in the function call
CurGen = app.Gen(GenNo);
% Pair the chromosomes randomly. The number of pairs would be
% half the population size. If a pair A&B has been chosen no
% other pair A&B or B&A should be chosen but each can still be
% paired with any other chromosome i.e. A&C would be valid
% likewise D&B
CurGen.crossPairs = ones(popSize/2,2);
for i = 1:popSize/2
% Get a random pair of the chromosoms
CurGen.crossPairs(i,:) = randi(popSize,1,2);
% Track pairing error
repErr = 1;
if i ~= 1
% The current pairing is not the first
while repErr
% Check if current pairing exist ealier
check1 = CurGen.crossPairs(i,:) == CurGen.crossPairs(1:i-1,:);
% Check if current pairing exists ealier in reverse
check2 = CurGen.crossPairs(i,:) == CurGen.crossPairs(1:i-1,[2 1]);
% Check if the current pairing is same i.e. having
% A&A
check3 = CurGen.crossPairs(i,1) == CurGen.crossPairs(i,2);
if (any(all(check1,2)) || any(all(check2,2)) || check3)
% If there is any pairing error pair again
CurGen.crossPairs(i,:) = randi(popSize,1,2);
else
% If there are no pairing error break out from
% pairing again
repErr = 0;
end
end
else
% The current pairing is the first
while repErr
if CurGen.crossPairs(i,1) == CurGen.crossPairs(i,2)
% Check if the current pairing is same i.e. having
% A&A if so repair
CurGen.crossPairs(i,:) = randi(popSize,1,2);
else
% If no pairing error do not pair again
repErr = 0;
end
end
end
end
% Generate random cross-over probabilty for each pairs. A
% probabilty should be generated for each strings i.e. each
% pairs should have number of probabilities equal to the number
% of strings
CurGen.crossProbs = rand(popSize/2,strNo);
% If the cross-over type is 1-point crossover generate one
% crossover point for each pair else (if cross-over type is
% 2-points cross-over) generate two cross-over points for each
% pair both points must not be the same
if app.PointButton.Value
CurGen.crossPoints = randi(bits-1,popSize/2,1);
else
CurGen.crossPoints = zeros(popSize/2,2);
for j = 1:popSize/2
while CurGen.crossPoints(j,1) == CurGen.crossPoints(j,2)
genNums = randi(bits,1,2)-1;
CurGen.crossPoints(j,1) = max(genNums);
CurGen.crossPoints(j,2) = min(genNums);
end
end
end
% Check where the cross-over probability generated is lesser
% than the specified general cross-over probability from onset.
% If the cross-over probability generated is lesser than the
% general cross-over probability for a string pair, there would
% be cross-over for such string pair
CurGen.doCross = CurGen.crossProbs <= app.CrossOverProbabilityEditField.Value;
% Do cross-over where required
CurGen.crossedPop = strings(size(CurGen.initPop));
for i = 1:size(CurGen.doCross,1)
% Loop through pairs
for j = 1:size(CurGen.doCross,2)
% Loop through strings
if CurGen.doCross(i,j)
% Current string pairs meet the criteria for cross-over
a = char(CurGen.initPop(CurGen.crossPairs(i,1),j));
b = char(CurGen.initPop(CurGen.crossPairs(i,2),j));
c = a;
if app.PointButton.Value
% If type of cross-over is 1-point, exchange the
% bits (digits) from the right up to the cross-over
% point
a(end-CurGen.crossPoints(i)+1:end) = b(end-CurGen.crossPoints(i)+1:end);
b(end-CurGen.crossPoints(i)+1:end) = c(end-CurGen.crossPoints(i)+1:end);
else
% If the type of cross-over is 2-points,
% exchange the bits (digits) between the cross
% points. Counting is from the left i.e. if 2 &
% 0 are generated, the last two digits would be
% exchanged likewise if 4 & 1 are generated the
% 3 digits before the last digit are exchanged
a(end-CurGen.crossPoints(i,1)+1:end-CurGen.crossPoints(i,2)) = ...
b(end-CurGen.crossPoints(i,1)+1:end-CurGen.crossPoints(i,2));
b(end-CurGen.crossPoints(i,1)+1:end-CurGen.crossPoints(i,2)) = ...
c(end-CurGen.crossPoints(i,1)+1:end-CurGen.crossPoints(i,2));
end
% If the type of value is real, check wether the
% values have gone more or less than the max range
% and min range respectively. If a value goes more
% than the max range it is set to max range else if
% it goes below min range it is set to min range
if app.TypeofValuesDropDown.Value == 2
if str2double(a)*10^-app.DecimalPlacesEditField.Value < app.Rng(j,1)
CurGen.crossedPop(i*2-1,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,1)*10^decPl);
elseif str2double(a)*10^-app.DecimalPlacesEditField.Value > app.Rng(j,2)
CurGen.crossedPop(i*2-1,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,2)*10^decPl);
else
CurGen.crossedPop(i*2-1,j) = string(a);
end
if str2double(b)*10^-app.DecimalPlacesEditField.Value < app.Rng(j,1)
CurGen.crossedPop(i*2,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,1)*10^decPl);
elseif str2double(b)*10^-app.DecimalPlacesEditField.Value > app.Rng(j,2)
CurGen.crossedPop(i*2,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,2)*10^decPl);
else
CurGen.crossedPop(i*2,j) = string(b);
end
else
CurGen.crossedPop(i*2-1,j) = string(a);
CurGen.crossedPop(i*2,j) = string(b);
end
else
% No checking is needed if the type of value is
% binary
CurGen.crossedPop([i*2-1 i*2],j) = ...
CurGen.initPop([CurGen.crossPairs(i,1) CurGen.crossPairs(i,2)],j);
end
end
end
end
function CurGen = mutate(app,GenNo)
% This function does mutation where neccesary
% Get the population size
popSize = app.PopulationSizeEditField.Value;
% Get the number of chromosomes
strNo = app.StringsPerChromosomeEditField.Value;
% Get the number of bits per chromosome
bits = app.BitsPerStringEditField.Value;
% Get the number of decimal places
decPl = app.DecimalPlacesEditField.Value;
% Get the generation to work on according to the number
% specified in the function call
CurGen = app.Gen(GenNo);
% Pair the chromosomes randomly. The number of pairs would be
% half the population size. If a pair A&B has been chosen no
% other pair A&B or B&A should be chosen but each can still be
% paired with any other chromosome i.e. A&C would be valid
% likewise D&B
CurGen.mutPairs = ones(popSize/2,2);
for i = 1:popSize/2
% Get a random pair of the chromosomes
CurGen.mutPairs(i,:) = randi(popSize,1,2);
% Track pairing error
repErr = 1;
if i ~= 1
% The current pairing is not the first
while repErr
% Check if current pairing exist ealier
check1 = CurGen.mutPairs(i,:) == CurGen.mutPairs(1:i-1,:);
% Check if current pairing exists ealier in reverse
check2 = CurGen.mutPairs(i,:) == CurGen.mutPairs(1:i-1,[2 1]);
% Check if the current pairing is same i.e. having
% A&A
check3 = CurGen.mutPairs(i,1) == CurGen.mutPairs(i,2);
if (any(all(check1,2)) || any(all(check2,2)) || check3)
% If there is any pairing error pair again
CurGen.mutPairs(i,:) = randi(popSize,1,2);
else
% If there are no pairing error break out from
% pairing again
repErr = 0;
end
end
else
% The current pairing is the first
while repErr
if CurGen.mutPairs(i,1) == CurGen.mutPairs(i,2)
% Check if the current pairing is same i.e. having
% A&A if so repair
CurGen.mutPairs(i,:) = randi(popSize,1,2);
else
% If no pairing error do not pair again
repErr = 0;
end
end
end
end
% Generate random mutation probabilty for each pairs. A
% probabilty should be generated for each strings i.e. each
% pairs should have number of probabilities equal to the number
% of strings
CurGen.mutProbs = rand(popSize/2,strNo);
% Generated a random mutation point between 1 and bits
CurGen.mutPoints = randi(bits,popSize/2,1);
% Check where the mutation probability generated is lesser
% than the specified general mutation probability from onset.
% If the mutation probability generated is lesser than the
% general mutation probability for a string pair, there would
% be mutation for such string pair
CurGen.doMutation = CurGen.mutProbs <= app.MutationProbabilityEditField.Value;
% Mutate where required
CurGen.mutatedPop = strings(size(CurGen.crossedPop));
for i = 1:size(CurGen.doMutation,1)
% Loop through pairs
for j = 1:size(CurGen.doMutation,2)
% Loop through strings
if CurGen.doMutation(i,j)
% Current string pairs meet the criteria for mutation
a = char(CurGen.crossedPop(CurGen.mutPairs(i,1),j));
b = char(CurGen.crossedPop(CurGen.mutPairs(i,2),j));
c = a;
% Exchange the bits (digits) from the right up to
% the mutation point
a(end-CurGen.mutPoints(i)+1) = b(end-CurGen.mutPoints(i)+1);
b(end-CurGen.mutPoints(i)+1) = c(end-CurGen.mutPoints(i)+1);
% If the type of value is real, check wether the
% values have gone more or less than the max range
% and min range respectively. If a value goes more
% than the max range it is set to max range else if
% it goes below min range it is set to min range
if app.TypeofValuesDropDown.Value == 2
if str2double(a)*10^-decPl < app.Rng(j,1)
CurGen.mutatedPop(i*2-1,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,1)*10^decPl);
elseif str2double(a)*10^-decPl > app.Rng(j,2)
CurGen.mutatedPop(i*2-1,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,2)*10^decPl);
else
CurGen.mutatedPop(i*2-1,j) = string(a);
end
if str2double(b)*10^-decPl < app.Rng(j,1)
CurGen.mutatedPop(i*2,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,1)*10^decPl);
elseif str2double(b)*10^-decPl > app.Rng(j,2)
CurGen.mutatedPop(i*2,j) = sprintf("%0"+...
string(bits)+"d",app.Rng(j,2)*10^decPl);
else
CurGen.mutatedPop(i*2,j) = string(b);
end
else
% No checking is needed if the type of value is
% binary
CurGen.mutatedPop(i*2-1,j) = string(a);
CurGen.mutatedPop(i*2,j) = string(b);
end
else
% No mutation
CurGen.mutatedPop([i*2-1 i*2],j) = ...
CurGen.crossedPop([CurGen.mutPairs(i,1) CurGen.mutPairs(i,2)],j);
end
end
end
end
function CurGen = evaluate(app,GenNo)
% This function evaluates the the generation corresponding to
% GenNo
% Get the population size
popSize = app.PopulationSizeEditField.Value;
% Get the number of strings per chromosome
strNo = app.StringsPerChromosomeEditField.Value;
% get the number of bits per chromosomes
bits = app.BitsPerStringEditField.Value;
% Get the number of decimal places
decPl = app.DecimalPlacesEditField.Value;
% If the GenNo is 0, work on Genzero else work on the the
% specified generation in Gen
if GenNo == 0
CurGen = app.GenZero;
else
CurGen = app.Gen(GenNo);
end
% Covert the user specified function to an anonymous function
% that can be worked with
fitFunc = str2func("@("+strjoin("x"+string(1:strNo),',')+")"+...
app.FunctionEditField.Value); %#ok<NASGU>
% Get the function value for each chromosome. If type is binary
% get denary values (denVal) and decoded values (decVal) first
% else if type is real just get the decoded values (decVal)
% first denary values are not needed
CurGen.fx = zeros(popSize,1);
if app.TypeofValuesDropDown.Value == 1
CurGen.denVal = zeros(popSize,strNo);
CurGen.decVal = zeros(popSize,strNo);
for i = 1:popSize
for j = 1:strNo
CurGen.denVal(i,j) = bin2dec(CurGen.initPop(i,j));
CurGen.decVal(i,j) = app.Rng(j,1) + (app.Rng(j,2)-app.Rng(j,1))*...
CurGen.denVal(i,j)/(2^bits-1);
end
CurGen.fx(i) = eval("fitFunc("+strjoin(string(CurGen.decVal(i,:)),...
',')+")");
end
else
CurGen.decVal = zeros(popSize,strNo);
for i = 1:popSize
for j = 1:strNo
CurGen.decVal(i,j) = str2double(CurGen.initPop(i,j))*10^-decPl;
end
CurGen.fx(i) = eval("fitFunc("+strjoin(string(CurGen.decVal(i,:)),...
',')+")");
end
end
% If the objective is minimization the fitness of each
% chromosome is the reciprocal of the function value else if
% the objective is maximization the fitness is same as the
% function value
if app.MinMaxDropDown.Value == 1
CurGen.fit = 1./CurGen.fx;
else
CurGen.fit = CurGen.fx;
end
end
function CurGen = select(app,GenNo)
% This function performs the selection of chromosomes to the
% next generation
% If the GenNo is 0, work on Genzero else work on the the
% specified generation in Gen
if GenNo == 0
CurGen = app.GenZero;
else
CurGen = app.Gen(GenNo);
end
% Get the cummulative fitness
CurGen.cumFit = cumsum(CurGen.fit);
% Get the maxi fitness for this generation as well as the
% chromosome having the max fitness
[maxfit,ind] = max(CurGen.fit);
% Update the best chromosome and best fitness till now if
% neccesary
if (GenNo==0)
% For the initial generation the best chromosome and
% fitness are the best till date
CurGen.bestFitTillNow = maxfit;
CurGen.bestTillNow = CurGen.initPop(ind,:);
elseif GenNo >= 2
% Gen 2 upwards
% If the current best is better than the best till the
% generation before update the best else the best remains
% the best
if maxfit >= app.Gen(GenNo-1).bestFitTillNow
CurGen.bestFitTillNow = maxfit;
CurGen.bestTillNow = CurGen.initPop(ind,:);
else
CurGen.bestFitTillNow = app.Gen(GenNo-1).bestFitTillNow;
CurGen.bestTillNow = app.Gen(GenNo-1).bestTillNow;
end
else
% If the current best is better than the best in generation
% zero update the best else the best remains the best
if maxfit >= app.GenZero.bestFitTillNow
CurGen.bestFitTillNow = maxfit;
CurGen.bestTillNow = CurGen.initPop(ind,:);
else
CurGen.bestFitTillNow = app.GenZero.bestFitTillNow;
CurGen.bestTillNow = app.GenZero.bestTillNow;
end
end
% Next select the chromosomes going to the next generation
CurGen.finalPop = strings(size(CurGen.initPop));
% Get the sort indices for sorting the chromosomes according