#Demanda dkji [grupo[dose[unidade]]]
import random
import numpy
import copy
import matplotlib.pyplot as plt
from timeit import default_timer as timer


demanda = [
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,132,112,95,81], [1727,929,243,1186,4838,1972,17395,6639,8851,13277,6638,3319,1660,830,415,207,104,52,26,13,6,1972,1676,1425,1211,1029], [2289,1884,372,752,10360,1781,61895,38832,41525,62288,31144,15572,7786,3893,1946,973,487,243,122,61,30,1781,1514,1287,1094,930], [0,154,4,34,426,19,953,730,3559,5339,2669,1335,667,334,167,83,42,21,10,5,3,19,16,14,12,10], [1728,1108,223,672,6588,1656,38053,29297,42681,64022,32011,16005,8003,4001,2001,1000,500,250,125,63,31,1656,1408,1196,1017,864]],#GP1
[[1557,8074,9444,1537,17193,6594,52382,40101,116365,174548,87274,43637,21818,10909,5455,2727,1364,682,341,170,85,6594,5605,4764,4050,3442], [9644,27195,55348,319,18857,18220,151458,42545,560430,840645,420323,210161,105081,52540,26270,13135,6568,3284,1642,821,410,18220,15487,13164,11189,9511], [4530,39496,10327,12073,82023,46448,437880,373380,697965,1046948,523474,261737,130868,65434,32717,16359,8179,4090,2045,1022,511,46448,39481,33559,28525,24246], [10,41,872,8,82,85,470,145,1838,2757,1379,689,345,172,86,43,22,11,5,3,1,85,72,61,52,44], [2568,25803,7126,4432,28852,31075,149280,78664,267589,401384,200692,100346,50173,25086,12543,6272,3136,1568,784,392,196,31075,26414,22452,19084,16221]],#GP10
[[16514,85643,100174,16306,182377,69944,555638,425369,1234329,1851494,925747,462873,231437,115718,57859,28930,14465,7232,3616,1808,904,69944,59452,50535,42954,36511], [6488,31648,22011,2981,37576,35399,249773,339222,135972,203958,101979,50990,25495,12747,6374,3187,1593,797,398,199,100,35399,30089,25576,21739,18478], [10217,58195,62620,10273,12559,2845,57883,120916,122865,184298,92149,46074,23037,11519,5759,2880,1440,720,360,180,90,2845,2418,2056,1747,1485], [11,134,652,11,113,163,724,1148,1244,1866,933,467,233,117,58,29,15,7,4,2,1,163,139,118,100,85], [3355,16547,51910,1789,2116,1031,7581,5513,34117,51176,25588,12794,6397,3198,1599,800,400,200,100,50,25,1031,876,745,633,538]],#GP11
[[65808,341283,399189,64977,726761,278722,2214183,1695067,4918723,7378085,3689042,1844521,922261,461130,230565,115283,57641,28821,14410,7205,3603,278722,236914,201377,171170,145495], [50,13610,4487,2132,151,91,835,6385,0,0,0,0,0,0,0,0,0,0,0,0,0,91,77,66,56,48], [459,1781,69684,1813,246,601,1206,1539,5,8,4,2,1,0,0,0,0,0,0,0,0,601,511,434,369,314], [0,63,63,5,43,29,3,47,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [52,100,18325,39,119,476,896,631,11,17,8,4,2,1,1,0,0,0,0,0,0,476,405,344,292,248]],#GP12
[[18819,97596,114155,18581,207830,79705,633183,484733,1406593,2109890,1054945,527472,263736,131868,65934,32967,16484,8242,4121,2060,1030,79705,67749,57587,48949,41607], [6,2,81,12,123,12,212,1071,2,3,2,1,0,0,0,0,0,0,0,0,0,12,10,9,7,6], [16,2,63,20,8,148,348,2644,6,9,5,2,1,1,0,0,0,0,0,0,0,148,126,107,91,77], [0,0,1,0,85,0,0,66,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [13,1,6,11,7,131,257,1828,7,11,5,3,1,1,0,0,0,0,0,0,0,131,111,95,80,68]],#GP13
[[393,2038,2384,388,4340,1664,13221,10121,29370,44055,22028,11014,5507,2753,1377,688,344,172,86,43,22,1664,1414,1202,1022,869], [0,0,0,0,0,1,2,20,277,416,208,104,52,26,13,6,3,2,1,0,0,1,1,1,1,1], [0,0,0,0,5,13,3,36,6424,9636,4818,2409,1205,602,301,151,75,38,19,9,5,13,11,9,8,7], [0,0,0,0,0,0,0,10,7,11,5,3,1,1,0,0,0,0,0,0,0,29,25,21,18,15], [0,0,0,0,2,4,3,25,2057,3086,1543,771,386,193,96,48,24,12,6,3,2,131,111,95,80,68]],#GP14
[[2541,13176,15411,2509,28058,10760,85481,65440,189894,284841,142421,71210,35605,17803,8901,4451,2225,1113,556,278,139,10760,9146,7774,6608,5617], [48,55,24,0,0,57,650,2374,1,2,1,0,0,0,0,0,0,0,0,0,0,57,48,41,35,30], [377,280,41,30,10,436,1674,848,1,2,1,0,0,0,0,0,0,0,0,0,0,436,371,315,268,228], [0,0,0,0,0,0,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [3,109,10,0,15,40,135,112,2,3,2,1,0,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP15
[[7332,38021,44473,7239,80967,31052,246676,188843,547982,821973,410987,205493,102747,51373,25687,12843,6422,3211,1605,803,401,31052,26394,22435,19070,16209], [1,530,463,1,2,7,106,352,26206,39309,19655,9827,4914,2457,1228,614,307,154,77,38,19,7,6,5,4,4], [3,833,3749,3,6,67,18,382,179913,269870,134935,67467,33734,16867,8433,4217,2108,1054,527,264,132,67,57,48,41,35], [0,1,0,0,0,0,0,30,385,578,289,144,72,36,18,9,5,2,1,1,0,29,25,21,18,15], [0,4,2660,2,6,57,11,316,4416,6624,3312,1656,828,414,207,104,52,26,13,6,3,131,111,95,80,68]],#GP16
[[2132,11057,12933,2105,23546,9030,71736,54918,159359,239039,119519,59760,29880,14940,7470,3735,1867,934,467,233,117,9030,7676,6524,5546,4714], [0,1,3,0,0,7,107,57,5,8,4,2,1,0,0,0,0,0,0,0,0,7,6,5,4,4], [2,28,776,1,9,145,15,235,54,81,41,20,10,5,3,1,1,0,0,0,0,145,123,105,89,76], [0,0,2,0,0,1,3,13,1,2,1,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [1,2,538,0,1,132,16,179,2,3,2,1,0,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP17
[[2227,11551,13511,2199,24599,9434,74943,57373,166483,249725,124862,62431,31216,15608,7804,3902,1951,975,488,244,122,9434,8019,6816,5794,4925], [164,542,2251,845,2438,955,4281,21239,241,362,181,90,45,23,11,6,3,1,1,0,0,955,812,690,586,499], [1149,3056,6218,1082,2309,5783,10446,3945,12,18,9,5,2,1,1,0,0,0,0,0,0,5783,4916,4178,3551,3019], [0,4,6,16,4,9,20,48,4,6,3,2,1,0,0,0,0,0,0,0,0,29,25,21,18,15], [105,1149,2095,110,192,1152,2356,964,16,24,12,6,3,2,1,0,0,0,0,0,0,131,111,95,80,68]],#GP18
[[2027,10514,12298,2002,22390,8587,68215,52222,151538,227307,113654,56827,28413,14207,7103,3552,1776,888,444,222,111,8587,7299,6204,5273,4482], [0,0,2,0,0,4,32,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,3,3,2,2], [2,2,0,0,31,4,17,57,0,0,0,0,0,0,0,0,0,0,0,0,0,4,3,3,2,2], [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [2,1,1,0,26,2,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP19
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,195,166,141,120,102], [0,2,4,0,2,2,314,415,2534,3801,1901,950,475,238,119,59,30,15,7,4,2,4,3,3,2,2], [15,30,53,80,293,195,1785,2029,4522,6783,3392,1696,848,424,212,106,53,26,13,7,3,195,166,141,120,102], [0,1,0,6,0,0,31,80,572,858,429,215,107,54,27,13,7,3,2,1,0,29,25,21,18,15], [13,17,49,73,135,190,1616,1800,3363,5045,2522,1261,631,315,158,79,39,20,10,5,2,131,111,95,80,68]],#GP2
[[221,1145,1339,218,2438,935,7427,5686,16499,24749,12374,6187,3094,1547,773,387,193,97,48,24,12,935,795,676,574,488], [0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,3,3,2,2], [0,0,2,0,1,6,1,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,5,4,4,3], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [0,0,0,0,3,1,0,2,9,14,7,3,2,1,0,0,0,0,0,0,0,131,111,95,80,68]],#GP20
[[350,1814,2122,345,3864,1482,11772,9012,26151,39227,19613,9807,4903,2452,1226,613,306,153,77,38,19,1482,1260,1071,910,774], [0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,4,3,3,2,2], [0,0,4,0,0,3,1,10,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,2,2,2], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [0,0,4,0,0,1,0,1,5,8,4,2,1,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP21
[[125,646,756,123,1375,528,4191,3208,9309,13964,6982,3491,1745,873,436,218,109,55,27,14,7,528,449,381,324,276], [0,0,16,2,0,0,1,0,1,2,1,0,0,0,0,0,0,0,0,0,0,4,3,3,2,2], [3,2,13,0,0,15,2,1,1,2,1,0,0,0,0,0,0,0,0,0,0,15,13,11,9,8], [0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [3,0,7,0,0,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP22
[[3730,19345,22627,3683,41194,15799,125504,96080,278803,418205,209102,104551,52276,26138,13069,6534,3267,1634,817,408,204,15799,13429,11415,9703,8247], [0,0,1,4,1,1,11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,3,3,2,2], [1,1,0,0,0,1,11,15,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1], [0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [1,1,1,0,0,1,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP23
[[334,1731,2025,330,3687,1414,11233,8599,24953,37430,18715,9357,4679,2339,1170,585,292,146,73,37,18,1414,1202,1022,868,738], [0,0,1,0,2,0,2,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,3,3,2,2], [3,0,10,0,0,2,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,25,21,18,15], [1,0,7,0,0,0,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP24
[[16002,82989,97070,15800,176726,67777,538420,412187,1196080,1794120,897060,448530,224265,112133,56066,28033,14017,7008,3504,1752,876,67777,57610,48969,41624,35380], [0,0,1,39,0,0,17,14,0,0,0,0,0,0,0,0,0,0,0,0,0,131,111,95,80,68], [1,0,1,0,2,3,12,56,1,2,1,0,0,0,0,0,0,0,0,0,0,3,3,2,2,2], [0,0,0,0,0,0,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,131,111,95,80,68], [0,1,0,0,0,3,6,22,0,0,0,0,0,0,0,0,0,0,0,0,0,131,111,95,80,68]],#GP25
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593], [0,253,135,0,2,58,20,443,299,449,224,112,56,28,14,7,4,2,1,0,0,58,49,42,36,30], [7019,7261,59945,4180,18423,125,6926,12159,3616,5424,2712,1356,678,339,170,85,42,21,11,5,3,125,106,90,77,65], [0,0,4,0,5,3,0,4,15,23,11,6,3,1,1,0,0,0,0,0,0,29,25,21,18,15], [4329,6530,35415,3452,17180,50,6359,9777,3243,4865,2432,1216,608,304,152,76,38,19,10,5,2,50,43,36,31,26]],#GP3
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593], [5888,7380,9336,6930,66841,15231,190203,127765,506775,760163,380081,190041,95020,47510,23755,11878,5939,2969,1485,742,371,15231,12946,11004,9354,7951], [13867,73325,84256,11923,288792,89498,355612,301314,1019475,1529213,764606,382303,191152,95576,47788,23894,11947,5973,2987,1493,747,89498,76073,64662,54963,46719], [774,215,1649,2429,6932,4647,19508,45101,69825,104738,52369,26184,13092,6546,3273,1637,818,409,205,102,51,4647,3950,3357,2854,2426], [10614,64682,73740,10297,222163,70393,285903,228277,888575,1332863,666431,333216,166608,83304,41652,20826,10413,5206,2603,1302,651,70393,59834,50859,43230,36746]],#GP4
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593], [5438,12815,25744,485,30587,22412,14387,29565,102801,154202,77101,38550,19275,9638,4819,2409,1205,602,301,151,75,22412,19050,16193,13764,11699], [1344,29442,2423,5282,91384,15939,332526,200951,699361,1049042,524521,262260,131130,65565,32783,16391,8196,4098,2049,1024,512,15939,13548,11516,9789,8320], [20,106,11075,12,2054,126,81,177,945,1418,709,354,177,89,44,22,11,6,3,1,1,126,107,91,77,66], [975,26106,1596,4338,55664,13700,276619,171247,606440,909660,454830,227415,113708,56854,28427,14213,7107,3553,1777,888,444,13700,11645,9898,8414,7151]],#GP5
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593], [5438,12815,25744,485,30587,22412,14387,29565,102801,154202,77101,38550,19275,9638,4819,2409,1205,602,301,151,75,22412,19050,16193,13764,11699], [1344,29442,2423,5282,91384,15939,332526,200951,699361,1049042,524521,262260,131130,65565,32783,16391,8196,4098,2049,1024,512,15939,13548,11516,9789,8320], [20,106,11075,12,2054,126,81,177,945,1418,709,354,177,89,44,22,11,6,3,1,1,126,107,91,77,66], [975,26106,1596,4338,55664,13700,276619,171247,606440,909660,454830,227415,113708,56854,28427,14213,7107,3553,1777,888,444,13700,11645,9898,8414,7151]],#GP6
[[721,3738,4372,712,7959,3052,24249,18564,53868,80802,40401,20201,10100,5050,2525,1263,631,316,158,79,39,3052,2594,2205,1874,1593], [2463,0,29349,2265,0,0,2463,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593], [3799,0,2425,191,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593], [2,0,48,4,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593], [492,0,309,86,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3052,2594,2205,1874,1593]],#GP7
[[2402,12456,14570,2372,26526,10173,80814,61867,179526,269289,134645,67322,33661,16831,8415,4208,2104,1052,526,263,131,10173,8647,7350,6247,5310], [0,4747,1064,3146,267,0,29192,8250,1813,2720,1360,680,340,170,85,42,21,11,5,3,1,2,2,1,1,1], [0,1,15,360,38,2,282,1185,5280,7920,3960,1980,990,495,248,124,62,31,15,8,4,2,2,1,1,1], [0,11,0,105,1,0,26,51,25,38,19,9,5,2,1,1,0,0,0,0,0,2,2,1,1,1], [0,0,0,109,0,2,104,1115,4241,6362,3181,1590,795,398,199,99,50,25,12,6,3,2,2,1,1,1]],#GP8
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,123,105,89,76], [4283,10571,38503,195,2674,1415,10252,10938,27885,41828,20914,10457,5228,2614,1307,654,327,163,82,41,20,1415,1203,1022,869,739], [6051,51300,6065,8013,135478,54865,482701,333067,1106997,1660496,830248,415124,207562,103781,51890,25945,12973,6486,3243,1622,811,54865,46635,39640,33694,28640], [20,45,12192,8,119,40,88,333,603,905,452,226,113,57,28,14,7,4,2,1,0,40,34,29,25,21], [5098,41263,4240,6140,58516,42222,348649,235910,860253,1290380,645190,322595,161297,80649,40324,20162,10081,5041,2520,1260,630,42222,35889,30505,25930,22040]]#GP9

           ]  

pesos = [
	 [0.083, 0.138,	 0.192,	 0.138,	 0.192],   #GP1	
	 [0.082, 0.137,	 0.191,	 0.137,	 0.191],   #GP2	
	 [0.081, 0.136,	 0.190,	 0.136,	 0.190],   #GP3	
	 [0.080, 0.134,	 0.189,	 0.134,	 0.189],   #GP4	
	 [0.079, 0.133,	 0.188,	 0.133,	 0.188],   #GP5	
	 [0.078, 0.132,	 0.187,	 0.132,	 0.187],   #GP6	
	 [0.077, 0.131,	 0.186,	 0.131,	 0.186],   #GP7	
	 [0.076, 0.130,	 0.185,	 0.130,	 0.185],   #GP8	
	 [0.075, 0.129,	 0.184,	 0.129,	 0.184],   #GP9	
	 [0.074, 0.128,	 0.183,	 0.128,	 0.183],   #GP10
	 [0.073, 0.127,	 0.182,	 0.127,	 0.182],   #GP11
	 [0.071, 0.126,	 0.181,	 0.126,	 0.181],   #GP12
	 [0.070, 0.125,	 0.180,	 0.125,	 0.180],   #GP13
	 [0.069, 0.124,	 0.178,	 0.124,	 0.178],   #GP14
	 [0.068, 0.123,	 0.177,	 0.123,	 0.177],   #GP15
	 [0.067, 0.122,	 0.176,	 0.122,	 0.176],   #GP16
	 [0.066, 0.121,	 0.175,	 0.121,	 0.175],   #GP17
	 [0.065, 0.120,	 0.174,	 0.120,	 0.174],   #GP18
	 [0.064, 0.119,	 0.173,	 0.119,	 0.173],   #GP19
	 [0.063, 0.118,	 0.172,	 0.118,	 0.172],   #GP20
	 [0.062, 0.116,	 0.171,	 0.116,	 0.171],   #GP21
	 [0.061, 0.115,	 0.170,	 0.115,	 0.170],   #GP22
	 [0.060, 0.114,	 0.169,	 0.114,	 0.169],   #GP23
	 [0.059, 0.113,	 0.168,	 0.113,	 0.168],    #GP24
	 [0.058, 0.112,	 0.167,	 0.112,  0.167]     #GP25	 
        ]

disponivel_coronavac = 60000000

disponivel_astrazeneca = 60000000


num_grupos = len(demanda)
num_unidades = len(demanda[0][0])

def get_random_alelo(grupo, dose, unidade, left = None):

    if left == None:
        if demanda[grupo][dose][unidade] == 0:
            return 0 
        else:
            return random.randrange(0, demanda[grupo][dose][unidade])
    else:
        safe_range = left if left < demanda[grupo][dose][unidade] else demanda[grupo][dose][unidade]
        if safe_range == 0:
            return 0 
        else:
            return random.randrange(0, safe_range)
 
def generate_solution():

    def randomly(seq):
        shuffled = list(seq)
        random.shuffle(shuffled)
        return iter(shuffled)


    coronavac_left = int(disponivel_coronavac * 0.9)
    astrazeneca_left = int(disponivel_astrazeneca * 0.9)

    solution = []
    for k in range(num_grupos):
        solution.append([])
        for j in range(6):
            solution[k].append([])
            for i in range(num_unidades):
                solution[k][j].append(-1)

    for k in randomly(range(num_grupos)):
        for j in randomly(range(6)):
            j_converted = 0 if j < 2 else j-1
            for i in randomly(range(num_unidades)):
                this_demand = demanda[k][j_converted][i] + 1
                if j == 0:
                    allocated_in_other_dose_1 =  solution[k][1][i]
                    if allocated_in_other_dose_1 != -1:
                        left_from_this_demand = this_demand - allocated_in_other_dose_1
                        if left_from_this_demand < coronavac_left:
                            alocadas = random.randrange(0, left_from_this_demand)
                        else:
                            alocadas = random.randrange(0, coronavac_left)
                    else:
                        alocadas = get_random_alelo(k, j_converted,  i, coronavac_left)
                    coronavac_left -= alocadas
                    solution[k][j][i] = alocadas
                elif j == 1:
                    allocated_in_other_dose_1 =  solution[k][0][i]
                    if allocated_in_other_dose_1 != -1:
                        left_from_this_demand = this_demand - allocated_in_other_dose_1
                        if left_from_this_demand < astrazeneca_left:
                            alocadas = random.randrange(0, left_from_this_demand)
                        else:
                            alocadas = random.randrange(0, astrazeneca_left)
                    else:
                        alocadas = get_random_alelo(k, j_converted,  i, astrazeneca_left)
                    astrazeneca_left -= alocadas
                    solution[k][j][i] = alocadas
                else:
                    if j == 0 or j == 2 or j == 6:
                        alocadas = get_random_alelo(k, j_converted,  i, coronavac_left)
                        coronavac_left -= alocadas
                    else:
                        alocadas = get_random_alelo(k, j_converted,  i, astrazeneca_left)
                        astrazeneca_left -= alocadas
                    solution[k][j][i] = alocadas
    return numpy.array(solution)

def is_feasible(solution):

    # Checar se D1A + D1C < D1
    for k in range(num_grupos):
        for i in range(num_unidades):
            if solution[k][0][i] + solution[k][1][i] > demanda[k][0][i]:
                return False

    # Checar se todas coronovac alocadas nao passam da disponibilidade
    atribuidas_coronavac = 0
    for k in range(num_grupos):
        for j in range(0, 6, 2):
            for i in range(num_unidades):
                atribuidas_coronavac += solution[k][j][i]
    if atribuidas_coronavac > disponivel_coronavac:
        # print("atribuidas_coronavac", atribuidas_coronavac)
        return False

    # Checar se todas coronovac alocadas nao passam da disponibilidade
    atribuidas_astrazeneca = 0
    for k in range(num_grupos):
        for j in range(1, 6, 2):
            for i in range(num_unidades):
                atribuidas_astrazeneca += solution[k][j][i]
    if atribuidas_astrazeneca > disponivel_astrazeneca:
        # print("atribuidas_astrazeneca", atribuidas_astrazeneca, disponivel_astrazeneca)
        return False

    return True

def get_Z(solution):

    accumulated_Z = 0

    for k in range(num_grupos):
            for j in range(6):
                for i in range(num_unidades):
                    j_converted = 0 if j < 2 else j-1
                    accumulated_Z += pesos[k][j_converted] * solution[k][j][i]

    return accumulated_Z

def generate_inital_population(population_size):
    population = []
    while(len(population) < population_size):
        solution = generate_solution()
        if is_feasible(solution) == True:
            # print(len(population)/population_size, end="\r")
            population.append(solution)
    return population

def evaluate_population(population):
    fitness = []
    for solution in population:
        Z = get_Z(solution)
        fitness.append(Z)
    return fitness

def selection(population, fitness):

    def select_solution(population, fitness):
        
        total_fitness = numpy.sum(fitness)
        probabilities = fitness/total_fitness

        choice = random.uniform(0,1)
        index_choice = -1

        for i in range(len(probabilities)):
            interval_start = numpy.sum(probabilities[:i])
            interval_end = interval_start + probabilities[i]
            if interval_start <= choice and choice <= interval_end:
                index_choice = i
        
        chosen_solution = population[index_choice]
        remaining_population = numpy.delete(population, index_choice, axis=0)
        remaining_fitness = numpy.delete(fitness, index_choice, axis=0)

        return (chosen_solution, remaining_population, remaining_fitness)

    population = numpy.array(population)
    fitness = numpy.array(fitness)

    sorted_index = numpy.argsort(fitness)

    sorted_population = population[sorted_index]
    sorted_fitness = fitness[sorted_index]

    remaining_population = sorted_population
    remaining_fitness = sorted_fitness
    pairs = []

    while len(remaining_population) > 0:
        chosen_solution_1, remaining_population, remaining_fitness = select_solution(remaining_population, remaining_fitness)
        chosen_solution_2, remaining_population, remaining_fitness = select_solution(remaining_population, remaining_fitness)
        pairs.append((chosen_solution_1, chosen_solution_2))

    return pairs

def crossover(parents):

    gene_num = 48

    children = []

    for couple in parents:
        children_are_feasible = False

        total_gene_num = 6 * num_grupos * num_unidades

        parent_1 = couple[0].reshape(total_gene_num)
        parent_2 = couple[1].reshape(total_gene_num)

        while not(children_are_feasible):
            split_index = random.randrange(0, gene_num)

            child_1 = numpy.concatenate((parent_1[:split_index], parent_2[split_index:]))
            child_2 = numpy.concatenate((parent_2[:split_index], parent_1[split_index:]))

            child_1 = child_1.reshape((num_grupos, 6, num_unidades))
            child_2 = child_2.reshape((num_grupos, 6, num_unidades))

            if is_feasible(child_1) and is_feasible(child_2):
                children.append(child_1)
                children.append(child_2)
                children_are_feasible = True
    
    return children

def mutation(children, mutation_probability):

    mutated_children = []

    for child in children:
        if random.uniform(0, 1) <= mutation_probability:
            
            new_child_is_feasible = False

            while not new_child_is_feasible:
                
                aux_child = copy.deepcopy(child)

                mutated_gene_k = random.randrange(0, num_grupos)
                mutated_gene_j = random.randrange(0, 6)
                mutated_gene_i = random.randrange(0, num_unidades)
                j_converted = 0 if mutated_gene_j < 2 else mutated_gene_j-1

                alelo = get_random_alelo(mutated_gene_k, j_converted, mutated_gene_i)

                aux_child[mutated_gene_k][mutated_gene_j][mutated_gene_i] = alelo

                new_child_is_feasible = is_feasible(aux_child)

            mutated_children.append(aux_child)
        else:
            mutated_children.append(copy.deepcopy(child))
    
    return mutated_children

def reinsertion(population, fitness, final_size):

    population = numpy.array(population, dtype='object')
    fitness = numpy.array(fitness)

    sorted_index = numpy.argsort(fitness)

    sorted_population = population[sorted_index]

    return (sorted_population[-final_size:])

def get_mean_Z(population):

    sum_of_Z = 0

    for solution in population:
        sum_of_Z += get_Z(solution)

    return sum_of_Z/len(population)

def get_distribution(solution):

    distribution = [0, 0, 0, 0, 0, 0]

    for k in range(num_grupos):
        for j in range(6):
            for i in range(num_unidades):
                distribution[j] += solution[k][j][i]

    return distribution

num_generations = 40
mean_Zs = []

start = timer()

# aleatorias e factiveis
population = generate_inital_population(500)

for gen in range(num_generations):

    fitness = evaluate_population(population)

    parents = selection(population, fitness)

    children = crossover(parents)
    
    children = mutation(children, 0.9)

    intermediate_population = numpy.concatenate((population, children))

    intermediate_population_fitness = evaluate_population(intermediate_population)

    new_population = reinsertion(intermediate_population, intermediate_population_fitness, len(population))

    population = copy.deepcopy(new_population)

    mean_Zs.append(get_mean_Z(population))

    # print(gen)

end = timer()
print(end - start)

plt.plot(range(num_generations), mean_Zs)

print(mean_Zs[-1])
print(get_distribution(population[0]))

plt.xlabel('Geracao')
plt.ylabel('Z medio')
plt.show()