From 4f622117d4bc6a74394a3883ddc31c499c146369 Mon Sep 17 00:00:00 2001 From: mopoa Date: Mon, 1 Sep 2025 10:49:29 +0330 Subject: [PATCH 1/8] adding multiprcessing to heuristics --- train_heuristics.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/train_heuristics.py b/train_heuristics.py index 9d79d0d..a53f3e3 100644 --- a/train_heuristics.py +++ b/train_heuristics.py @@ -1,5 +1,7 @@ +from multiprocessing import Process from env_creator import qsimpy_env_creator import os +import sys import csv import pandas as pd import matplotlib.pyplot as plt @@ -71,6 +73,8 @@ def run(self, control): arr_temp["total_completion_time"] += info["scheduled_qtask"].waiting_time + info["scheduled_qtask"].execution_time arr_temp["rescheduling_count"] += info["scheduled_qtask"].rescheduling_count + sys.stdout.write("\033[F\033[K") + print(f"progress: {len(self.results)}%") self.env.qsp_env.run() # Final results of the episode self.results.append(arr_temp) @@ -164,10 +168,15 @@ def _summarize_results(self, values, label) -> None: # Run the heuristic solutions heuristics = HeuristicSolutions(env, num_episodes=100) - heuristics.run("greedy") - heuristics.run("random") - heuristics.run("round_robin") - heuristics.run("greedy_error") + methods = ['greedy','random','round_robin','greedy_error'] + processes = [Process(target=heuristics.run , args=(m,)) for m in methods] + for i in range(len(methods)) : processes[i].start() + for i in range(len(methods)) : processes[i].join() + print("All Processes are done!!") + # heuristics.run("greedy") + # heuristics.run("random") + # heuristics.run("round_robin") + # heuristics.run("greedy_error") # Plot the results paths = [ From 49e540a169d3eb49a6fab0bd7f4e315ce217b281 Mon Sep 17 00:00:00 2001 From: mopoa Date: Tue, 2 Sep 2025 01:02:40 +0330 Subject: [PATCH 2/8] new train heuristic --- results/heuristics/greedy_error.csv | 202 ++++++++++++++-------------- results/heuristics/random.csv | 200 +++++++++++++-------------- results/heuristics/round_robin.csv | 200 +++++++++++++-------------- 3 files changed, 301 insertions(+), 301 deletions(-) diff --git a/results/heuristics/greedy_error.csv b/results/heuristics/greedy_error.csv index e5d68a5..98848a4 100644 --- a/results/heuristics/greedy_error.csv +++ b/results/heuristics/greedy_error.csv @@ -1,101 +1,101 @@ -Episode,Total Completion Time,Rescheduling Count -0,779.286564033785,44.0 -1,1018.0907645941475,46.0 -2,641.8455081869836,44.0 -3,654.0831900588066,44.0 -4,871.1009895371011,46.0 -5,585.3419575893722,40.0 -6,446.8945558944891,35.0 -7,512.7857438402183,36.0 -8,870.0392874462106,45.0 -9,1403.2538843569118,46.0 -10,437.20049371329264,43.0 -11,387.3112745833579,37.0 -12,241.9880555126875,40.0 -13,626.9781166282103,39.0 -14,780.902382522772,40.0 -15,388.4511046105547,35.0 -16,827.7077435577246,44.0 -17,607.3581004546566,43.0 -18,700.7635993222689,42.0 -19,499.64671161102183,48.0 -20,755.1151848860904,37.0 -21,395.14827467242446,37.0 -22,1118.8852805272445,44.0 -23,672.2494591832836,43.0 -24,752.6005621924559,40.0 -25,721.8238032533495,44.0 -26,207.0930613935666,28.0 -27,888.658573558916,44.0 -28,534.4488956052584,39.0 -29,1005.5085728583823,43.0 -30,853.3132124534151,41.0 -31,590.8656874378183,45.0 -32,461.01304465604215,36.0 -33,686.935225951273,40.0 -34,577.5721509951466,46.0 -35,716.722166899953,41.0 -36,625.5229764371421,41.0 -37,615.3195559790382,48.0 -38,780.3194866897076,38.0 -39,594.9541520086445,44.0 -40,561.3443611413669,43.0 -41,661.7754295462144,48.0 -42,571.6179140077627,42.0 -43,737.876597753784,44.0 -44,398.5770308682531,39.0 -45,593.1565609649705,41.0 -46,448.31888197741904,43.0 -47,739.4550793811899,45.0 -48,566.6025067912151,36.0 -49,488.08591091471266,46.0 -50,473.32301622092916,41.0 -51,702.8283220644104,43.0 -52,501.7041333591779,41.0 -53,859.9557336531625,45.0 -54,572.9886504975027,34.0 -55,682.6790300121812,39.0 -56,784.8824768279756,44.0 -57,524.2425649438379,44.0 -58,560.7080082720844,41.0 -59,470.0018740168153,41.0 -60,685.8348449770591,39.0 -61,578.3072927716473,41.0 -62,1037.7674743484838,47.0 -63,363.07834646054357,41.0 -64,975.0234557794759,44.0 -65,645.9724131814359,43.0 -66,572.6235504259654,37.0 -67,703.0491048629965,44.0 -68,816.9584956357872,42.0 -69,645.0645671546602,44.0 -70,601.470562470287,36.0 -71,792.2956085695879,45.0 -72,794.2921778200525,46.0 -73,687.8876958511382,38.0 -74,563.7197154668082,43.0 -75,810.3360229023112,48.0 -76,630.9707744234905,42.0 -77,808.783449981612,46.0 -78,760.8511106964423,44.0 -79,614.4434092193461,39.0 -80,476.1463679302302,36.0 -81,547.9441818033677,35.0 -82,545.6914809418145,35.0 -83,485.7904843422369,39.0 -84,450.62171141799803,42.0 -85,1073.4248717263085,48.0 -86,551.0077594549593,34.0 -87,825.3505545480989,44.0 -88,610.0023367103439,39.0 -89,697.8224633469039,41.0 -90,412.86652903623803,35.0 -91,769.2821875828371,42.0 -92,430.0895171689559,41.0 -93,955.1218764261479,44.0 -94,774.9226519278552,46.0 -95,410.0365030939497,37.0 -96,1256.3691795545785,46.0 -97,767.2365327297308,45.0 -98,752.0432471902363,47.0 -99,798.6604685050595,46.0 +Episode,Total Completion Time,Rescheduling Count +0,779.286564033785,44.0 +1,1018.0907645941475,46.0 +2,641.8455081869836,44.0 +3,654.0831900588066,44.0 +4,871.1009895371011,46.0 +5,585.3419575893722,40.0 +6,446.8945558944891,35.0 +7,512.7857438402183,36.0 +8,870.0392874462106,45.0 +9,1403.2538843569118,46.0 +10,437.20049371329264,43.0 +11,387.3112745833579,37.0 +12,241.9880555126875,40.0 +13,626.9781166282103,39.0 +14,780.902382522772,40.0 +15,388.4511046105547,35.0 +16,827.7077435577246,44.0 +17,607.3581004546566,43.0 +18,700.7635993222689,42.0 +19,499.64671161102183,48.0 +20,755.1151848860904,37.0 +21,395.14827467242446,37.0 +22,1118.8852805272445,44.0 +23,672.2494591832836,43.0 +24,752.6005621924559,40.0 +25,721.8238032533495,44.0 +26,207.0930613935666,28.0 +27,888.658573558916,44.0 +28,534.4488956052584,39.0 +29,1005.5085728583823,43.0 +30,853.3132124534151,41.0 +31,590.8656874378183,45.0 +32,461.01304465604215,36.0 +33,686.935225951273,40.0 +34,577.5721509951466,46.0 +35,716.722166899953,41.0 +36,625.5229764371421,41.0 +37,615.3195559790382,48.0 +38,780.3194866897076,38.0 +39,594.9541520086445,44.0 +40,561.3443611413669,43.0 +41,661.7754295462144,48.0 +42,571.6179140077627,42.0 +43,737.876597753784,44.0 +44,398.5770308682531,39.0 +45,593.1565609649705,41.0 +46,448.31888197741904,43.0 +47,739.4550793811899,45.0 +48,566.6025067912151,36.0 +49,488.08591091471266,46.0 +50,473.32301622092916,41.0 +51,702.8283220644104,43.0 +52,501.7041333591779,41.0 +53,859.9557336531625,45.0 +54,572.9886504975027,34.0 +55,682.6790300121812,39.0 +56,784.8824768279756,44.0 +57,524.2425649438379,44.0 +58,560.7080082720844,41.0 +59,470.0018740168153,41.0 +60,685.8348449770591,39.0 +61,578.3072927716473,41.0 +62,1037.7674743484838,47.0 +63,363.07834646054357,41.0 +64,975.0234557794759,44.0 +65,645.9724131814359,43.0 +66,572.6235504259654,37.0 +67,703.0491048629965,44.0 +68,816.9584956357872,42.0 +69,645.0645671546602,44.0 +70,601.470562470287,36.0 +71,792.2956085695879,45.0 +72,794.2921778200525,46.0 +73,687.8876958511382,38.0 +74,563.7197154668082,43.0 +75,810.3360229023112,48.0 +76,630.9707744234905,42.0 +77,808.783449981612,46.0 +78,760.8511106964423,44.0 +79,614.4434092193461,39.0 +80,476.1463679302302,36.0 +81,547.9441818033677,35.0 +82,545.6914809418145,35.0 +83,485.7904843422369,39.0 +84,450.62171141799803,42.0 +85,1073.4248717263085,48.0 +86,551.0077594549593,34.0 +87,825.3505545480989,44.0 +88,610.0023367103439,39.0 +89,697.8224633469039,41.0 +90,412.86652903623803,35.0 +91,769.2821875828371,42.0 +92,430.0895171689559,41.0 +93,955.1218764261479,44.0 +94,774.9226519278552,46.0 +95,410.0365030939497,37.0 +96,1256.3691795545785,46.0 +97,767.2365327297308,45.0 +98,752.0432471902363,47.0 +99,798.6604685050595,46.0 diff --git a/results/heuristics/random.csv b/results/heuristics/random.csv index bbc816a..5965701 100644 --- a/results/heuristics/random.csv +++ b/results/heuristics/random.csv @@ -1,101 +1,101 @@ Episode,Total Completion Time,Rescheduling Count -0,1478.5757952463066,15.0 -1,1330.0717844035278,30.0 -2,1358.4802022002825,14.0 -3,896.0747618793595,15.0 -4,1593.6304325693502,11.0 -5,1258.9852748962012,17.0 -6,1168.6295077047514,10.0 -7,939.3489087440826,25.0 -8,1317.2328963468426,12.0 -9,1026.1666454641281,5.0 -10,1779.2610736119923,9.0 -11,1065.4091749296842,9.0 -12,1113.8336344676886,10.0 -13,1271.9906573229684,8.0 -14,646.9844940702196,8.0 -15,722.5758079698842,19.0 -16,542.4364262618708,11.0 -17,1930.820470337957,26.0 -18,1532.3709399390386,19.0 -19,911.3854104249705,21.0 -20,1110.4689838317045,16.0 -21,826.8928272374625,13.0 -22,908.3708768892137,10.0 -23,1141.046644951563,12.0 -24,1036.1727285265406,16.0 -25,720.6487746534319,16.0 -26,856.415307628558,13.0 -27,662.4360868326567,7.0 -28,534.3095941428542,13.0 -29,1194.0801396555087,18.0 -30,731.8626413120057,12.0 -31,1048.5611447527035,12.0 -32,792.8744885216804,24.0 -33,1382.1510884776408,16.0 -34,700.6986682655009,10.0 -35,1370.850122338716,5.0 -36,789.7678264415608,14.0 -37,794.0932177655627,7.0 -38,1347.5809260895185,14.0 -39,575.5529914939242,8.0 -40,2789.7382001725864,20.0 -41,1843.8918971378828,13.0 -42,628.7543454347912,15.0 -43,1242.3926080693172,18.0 -44,1591.3038021635002,13.0 -45,733.5976211045506,18.0 -46,697.285717128637,9.0 -47,1004.1860794312714,14.0 -48,971.4523252511981,9.0 -49,782.7027681875801,9.0 -50,1096.0961398848933,15.0 -51,1702.1268987637109,13.0 -52,2911.3100280435533,28.0 -53,632.5023550220482,11.0 -54,1089.277243557256,8.0 -55,995.7650568151922,16.0 -56,1400.03726152878,10.0 -57,628.8026716452497,9.0 -58,976.5280579120243,4.0 -59,1566.4428430697599,16.0 -60,1517.8556731435378,11.0 -61,1286.4812745493296,16.0 -62,1041.0898217439374,19.0 -63,842.2850871374727,15.0 -64,963.8396078186036,15.0 -65,744.1331633393584,10.0 -66,901.5830860058976,9.0 -67,476.9874574733113,17.0 -68,663.6282355387759,8.0 -69,1103.5751434524334,20.0 -70,1390.1220640853858,13.0 -71,1000.9959229584504,10.0 -72,776.2366402936705,4.0 -73,1154.914863402619,9.0 -74,2047.6674411643612,14.0 -75,2667.05460364607,13.0 -76,887.3010218508851,8.0 -77,895.6278939051847,5.0 -78,1156.3472075100271,8.0 -79,678.8417681934935,11.0 -80,778.1908213720845,12.0 -81,1215.5078473397223,10.0 -82,998.1348328298731,11.0 -83,1408.2445364017726,8.0 -84,766.8626439732058,15.0 -85,890.0562179830085,6.0 -86,696.7525782879777,8.0 -87,881.5376001686645,15.0 -88,436.1512366383241,8.0 -89,876.1794201725302,9.0 -90,1018.4002073712784,13.0 -91,646.7646596599425,11.0 -92,2720.438865774572,16.0 -93,1474.6468750711817,9.0 -94,1586.7329733839,18.0 -95,1373.6813442230577,14.0 -96,1724.387722049794,12.0 -97,437.1704602696404,15.0 -98,1572.289318568651,7.0 -99,1032.2216660118052,15.0 +0,1347.0420317101161,15.0 +1,2134.615473591639,21.0 +2,931.6157167605069,11.0 +3,1149.997513162218,14.0 +4,1391.6838692913027,22.0 +5,639.2270410963438,8.0 +6,796.4860315595515,17.0 +7,1187.889997023277,10.0 +8,1227.0110787994006,7.0 +9,2528.731160124443,18.0 +10,625.776928852375,12.0 +11,583.9825487811677,10.0 +12,625.3597619992973,8.0 +13,1933.2817353580504,12.0 +14,1455.2642503744746,15.0 +15,547.954802710524,10.0 +16,1300.6682634247059,12.0 +17,789.7169707164147,11.0 +18,1884.4023780452133,12.0 +19,878.7414213461481,11.0 +20,1549.0828207597203,16.0 +21,520.3818429392153,11.0 +22,1196.4580030886875,19.0 +23,1094.760111361848,11.0 +24,1787.5626571175383,9.0 +25,2377.709538588765,14.0 +26,465.5393532371849,6.0 +27,1331.6933816422634,21.0 +28,848.3190501213164,8.0 +29,1317.1148989824885,12.0 +30,1440.8638159106113,24.0 +31,1422.63266536302,20.0 +32,1230.1264317323712,14.0 +33,1172.3158427171247,14.0 +34,600.6742274315427,22.0 +35,1137.5399491945614,17.0 +36,849.0172086392379,11.0 +37,707.8641183656605,16.0 +38,1131.2976618797368,19.0 +39,708.5972525763398,12.0 +40,777.3619729044475,13.0 +41,1062.9363573557137,20.0 +42,964.4460485745744,17.0 +43,982.303283973371,10.0 +44,674.477035347528,12.0 +45,1003.2072990075158,2.0 +46,974.0452370191756,21.0 +47,936.4548728614423,14.0 +48,951.8152151127535,26.0 +49,580.3156461007073,11.0 +50,846.9098703835471,16.0 +51,1804.7971919066913,7.0 +52,763.0649601246339,13.0 +53,1642.9519199126821,12.0 +54,997.6082886834663,21.0 +55,1015.6033879965863,18.0 +56,1281.138227784497,9.0 +57,899.7454975314889,8.0 +58,1004.1053884234485,11.0 +59,825.1421628577752,17.0 +60,1113.8294817673973,12.0 +61,1358.0867842858531,17.0 +62,1823.6408052985335,9.0 +63,702.3224742703404,5.0 +64,1526.5970898020755,12.0 +65,895.5619896043671,12.0 +66,1429.8304833933523,8.0 +67,1131.8710432049884,19.0 +68,870.2476880633367,19.0 +69,995.7250401435597,16.0 +70,1115.0837382107547,9.0 +71,1180.8408955445807,11.0 +72,1750.1793239157237,8.0 +73,779.3600443538534,8.0 +74,1149.045050708336,10.0 +75,948.9796049739532,5.0 +76,908.0352870548267,14.0 +77,879.4513685802084,14.0 +78,1362.5922868228806,12.0 +79,834.5922367523832,13.0 +80,745.6078788119031,6.0 +81,2043.474233659995,12.0 +82,728.9880108313126,8.0 +83,854.6309431034314,11.0 +84,551.1450535877735,18.0 +85,1662.035399053742,24.0 +86,1260.3175156009072,4.0 +87,1270.4618396547992,11.0 +88,753.2788098899683,17.0 +89,1818.749886676378,8.0 +90,1609.1234927051564,9.0 +91,1256.806940443047,19.0 +92,1288.5197175598275,9.0 +93,1513.908532729961,17.0 +94,858.4830049034177,17.0 +95,672.8613072154333,23.0 +96,2192.8170253518483,17.0 +97,1293.313628335685,9.0 +98,1730.8973118938827,11.0 +99,1382.6731211841375,19.0 diff --git a/results/heuristics/round_robin.csv b/results/heuristics/round_robin.csv index beddae4..d4b26d7 100644 --- a/results/heuristics/round_robin.csv +++ b/results/heuristics/round_robin.csv @@ -1,101 +1,101 @@ Episode,Total Completion Time,Rescheduling Count -0,896.6456654046958,12.0 -1,1871.0879022002375,16.0 -2,510.79570315056674,12.0 -3,824.1042787696023,13.0 -4,793.7566353584212,16.0 -5,1195.5185394703121,11.0 -6,1049.0003821311604,11.0 -7,529.3791395821091,7.0 -8,1118.336106206277,9.0 -9,673.4589619263967,13.0 -10,1469.0348603956381,11.0 -11,494.8463140046214,13.0 -12,793.3971136973067,12.0 -13,1100.5065892325117,12.0 -14,1591.2272687430552,13.0 -15,477.39917784322813,12.0 -16,1007.4534663044803,13.0 -17,958.4246494918717,13.0 -18,457.6562821021427,12.0 -19,503.66683242919765,7.0 -20,720.4785259890806,16.0 -21,874.4693058959571,13.0 -22,1044.4341061423006,11.0 -23,637.3702856308968,7.0 -24,1226.0152274772724,13.0 -25,598.0127872691697,16.0 -26,698.4138902971073,11.0 -27,1081.5844919875208,11.0 -28,1166.6331596861705,13.0 -29,756.227117050151,12.0 -30,1002.0314899664113,14.0 -31,775.3366726813233,13.0 -32,1007.9649681354205,12.0 -33,613.8010912606667,9.0 -34,805.781126111259,14.0 -35,1004.9199352993268,12.0 -36,1002.8114451253723,11.0 -37,1083.08481643458,12.0 -38,665.3124446637631,11.0 -39,1108.096700775744,14.0 -40,638.3453855845744,8.0 -41,498.09976703964713,12.0 -42,1015.830552685081,13.0 -43,1138.6822736859224,16.0 -44,633.7455602973097,5.0 -45,944.2120125318447,13.0 -46,828.9142438710427,11.0 -47,799.1685394622021,11.0 -48,1001.5054643858178,16.0 -49,680.4556417750368,7.0 -50,653.8649837420505,11.0 -51,515.6572095931972,13.0 -52,1319.0663130611722,11.0 -53,1013.0111902857732,12.0 -54,1386.6047380820037,16.0 -55,1129.9116464179374,12.0 -56,818.6890571057631,13.0 -57,839.8067544380015,12.0 -58,1379.5509489644949,13.0 -59,649.5536809931372,13.0 -60,956.2737942179783,12.0 -61,1096.2702825791414,11.0 -62,871.9568993703994,12.0 -63,833.2604699493944,12.0 -64,985.3178404348411,13.0 -65,739.4419406882281,13.0 -66,594.903416989284,13.0 -67,629.7017297275405,12.0 -68,859.9884263667459,16.0 -69,741.1079985813102,6.0 -70,1096.235995871185,13.0 -71,1077.06661046078,12.0 -72,744.8403333430768,12.0 -73,581.6590883388335,8.0 -74,723.1321970419509,9.0 -75,583.8902999476568,11.0 -76,863.0820192112726,8.0 -77,630.7861055399047,8.0 -78,780.8301014046206,13.0 -79,522.9615301998499,9.0 -80,330.4524344935783,12.0 -81,1108.5922830379768,11.0 -82,697.7588930036542,8.0 -83,1143.4940273168565,13.0 -84,965.190344518973,11.0 -85,1039.5953489887909,13.0 -86,756.1646445429772,13.0 -87,1233.6372212514466,16.0 -88,1136.2305108205057,12.0 -89,1346.8606566757437,16.0 -90,1247.0016497513018,11.0 -91,371.3166356704254,8.0 -92,779.4272937782516,13.0 -93,761.2030528745827,14.0 -94,860.4854299738633,11.0 -95,1020.7382699857077,12.0 -96,592.0044182627178,8.0 -97,1049.3217613015659,13.0 -98,1099.9249351141862,16.0 -99,656.064437356785,12.0 +0,1105.376982535404,12.0 +1,1487.6684240714526,14.0 +2,1003.9454052829486,11.0 +3,1038.8745393466731,12.0 +4,1299.1035864225507,14.0 +5,994.9267037608945,12.0 +6,642.1537110087992,8.0 +7,737.1246372992813,9.0 +8,1266.6174705125034,12.0 +9,1934.2820720795903,14.0 +10,652.6149793987391,10.0 +11,636.0353949093793,11.0 +12,789.8981706285971,12.0 +13,1040.7566042338756,12.0 +14,1215.5884795218835,12.0 +15,704.3389460643133,11.0 +16,1314.7420651045759,13.0 +17,1234.2307452908872,11.0 +18,1096.6470150406103,13.0 +19,754.8117563731232,16.0 +20,1167.8155382243372,13.0 +21,789.3921964899594,12.0 +22,1682.338749833467,16.0 +23,1079.7550885300163,12.0 +24,1237.240277197955,11.0 +25,1272.1298386988783,16.0 +26,554.4603024494769,10.0 +27,1338.7673269998438,13.0 +28,651.9116917076187,9.0 +29,1537.2516371550323,14.0 +30,1060.3157854764336,10.0 +31,830.8000676433368,12.0 +32,962.2197014223709,9.0 +33,934.7430027038413,11.0 +34,948.5813207350654,13.0 +35,1227.08337069528,12.0 +36,1005.2195554656358,11.0 +37,953.2724846087079,13.0 +38,1252.496288361309,14.0 +39,976.9133051419012,13.0 +40,1046.7601464907355,11.0 +41,850.3341641409071,14.0 +42,958.3598646810218,11.0 +43,893.7463361581605,9.0 +44,927.9703627988202,12.0 +45,1006.4689390288339,8.0 +46,768.5525667533906,13.0 +47,1182.2418362192568,16.0 +48,961.7663931039309,12.0 +49,1025.2304870150117,11.0 +50,899.5448370077687,11.0 +51,1167.0770991997883,11.0 +52,890.0898107826142,10.0 +53,1364.073845043698,11.0 +54,916.2213644557462,6.0 +55,956.7117000171296,11.0 +56,1181.8675687766424,12.0 +57,1021.2264185846531,12.0 +58,1075.0286915604843,12.0 +59,690.3136465964394,14.0 +60,1154.4542019049188,11.0 +61,956.843633572331,9.0 +62,1268.1779608738075,13.0 +63,724.7248347397484,14.0 +64,1194.0392870139685,13.0 +65,1274.136163978858,11.0 +66,995.482429491637,10.0 +67,1034.443320722132,11.0 +68,1046.9285281646203,10.0 +69,960.9734191296022,9.0 +70,1141.5371305704841,11.0 +71,1173.980757277937,12.0 +72,1014.9297784836522,13.0 +73,928.5376868243017,12.0 +74,1239.187034726945,11.0 +75,1145.5754732057958,13.0 +76,1070.0248707854594,12.0 +77,1149.8336527963938,16.0 +78,1213.4202684400466,16.0 +79,1122.8360064094782,12.0 +80,797.2862170541603,8.0 +81,1187.712529888232,13.0 +82,1225.9002452063523,11.0 +83,756.29929972232,12.0 +84,691.1052330532966,7.0 +85,1249.0359355328233,12.0 +86,981.310828836232,10.0 +87,1243.2875428842135,13.0 +88,814.6823990524504,13.0 +89,1197.5476126673075,13.0 +90,712.9938393102277,7.0 +91,1237.5586641138707,11.0 +92,949.349873557107,14.0 +93,1435.8744891001809,12.0 +94,1223.0608857483298,12.0 +95,600.5653083914607,10.0 +96,1424.3967832513704,14.0 +97,1068.4438512943414,14.0 +98,1269.3237905789406,13.0 +99,1079.0484036200105,13.0 From fa19357a1d649bca38845cebcf46967fad700005 Mon Sep 17 00:00:00 2001 From: mopoa Date: Sun, 7 Sep 2025 11:28:22 +0330 Subject: [PATCH 3/8] update gym-methods --- .gitignore | 5 ++++- env_creator.py | 6 +++--- env_wrapper.py | 2 +- ray_train_dqn.py | 5 ++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 4fffd9c..be4bd47 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ logs/ # Dependency directories venv/ +.venv/ env/ env.bak/ env.tmp/ @@ -46,4 +47,6 @@ env.production.local/ Thumbs.db # QASM files -*.qasm \ No newline at end of file +*.qasm + +results/* \ No newline at end of file diff --git a/env_creator.py b/env_creator.py index 61af8b9..bd91144 100644 --- a/env_creator.py +++ b/env_creator.py @@ -1,6 +1,6 @@ from gymenv_qsimpy import QSimPyEnv from env_wrapper import ScaleQSimPyEnv -from gymnasium.experimental.wrappers import RescaleObservationV0, DtypeObservationV0 +from gymnasium.wrappers import RescaleObservation, DtypeObservation import numpy as np @@ -16,12 +16,12 @@ def qsimpy_env_creator(env_config): if obs_filter is not None: if obs_filter == "rescale_-1_1": - env = RescaleObservationV0( + env = RescaleObservation( env=env, min_obs=np.ones((env.obs_dim,), dtype=np.float32) * -1, max_obs=np.ones((env.obs_dim,), dtype=np.float32) * 1, ) - env = DtypeObservationV0(env, dtype=np.float32) + env = DtypeObservation(env, dtype=np.float32) if reward_filter is not None: if reward_filter == "scale_2x": diff --git a/env_wrapper.py b/env_wrapper.py index bb5bd2d..9fc1327 100644 --- a/env_wrapper.py +++ b/env_wrapper.py @@ -1,6 +1,6 @@ import gymnasium as gym from gymnasium.core import Env -from gymnasium.wrappers.normalize import NormalizeObservation, NormalizeReward +from gymnasium.wrappers import NormalizeObservation, NormalizeReward import numpy as np from gymnasium.spaces import Box diff --git a/ray_train_dqn.py b/ray_train_dqn.py index 8ccab2f..dcc4b53 100644 --- a/ray_train_dqn.py +++ b/ray_train_dqn.py @@ -1,5 +1,4 @@ import argparse - import ray from ray import tune, air, train from ray.tune.registry import register_env @@ -12,7 +11,7 @@ tf1, tf, tfv = try_import_tf() parser = argparse.ArgumentParser() -parser.add_argument("--num-cpus", type=int, default=0) +parser.add_argument("--num-cpus", type=int, default=1) parser.add_argument( "--framework", @@ -68,7 +67,7 @@ v_min=-10.0, v_max=10.0, ) - .rollouts(num_rollout_workers=8) + .env_runners(num_env_runners=8) ) stop_config = { From 3df08d122dde44e4dc06eac16c4248714837b12c Mon Sep 17 00:00:00 2001 From: mopoa Date: Fri, 19 Sep 2025 15:39:01 +0330 Subject: [PATCH 4/8] WORKING_ UPDATED --- env_creator.py | 7 ++- env_wrapper.py | 51 ++++++++++++--- gymenv_qsimpy.py | 159 +++++++++++++++++++++++++++++++++++------------ ray_train_dqn.py | 26 +++----- 4 files changed, 176 insertions(+), 67 deletions(-) diff --git a/env_creator.py b/env_creator.py index bd91144..bf0ab97 100644 --- a/env_creator.py +++ b/env_creator.py @@ -1,5 +1,5 @@ from gymenv_qsimpy import QSimPyEnv -from env_wrapper import ScaleQSimPyEnv +from env_wrapper import ScaleQSimPyEnv , SerializableEnvWrapper from gymnasium.wrappers import RescaleObservation, DtypeObservation import numpy as np @@ -10,7 +10,10 @@ def qsimpy_env_creator(env_config): config = config if config is not None else {} if dataset is None: raise ValueError("Dataset is not specified") + env = QSimPyEnv(dataset=dataset, config=config) + env = SerializableEnvWrapper(env) + obs_filter = env_config.pop("obs_filter", None) reward_filter = env_config.pop("reward_filter", None) @@ -26,4 +29,6 @@ def qsimpy_env_creator(env_config): if reward_filter is not None: if reward_filter == "scale_2x": env = ScaleQSimPyEnv(env, scale=env_config.pop("reward_scale", 2)) + + for i in range(10) : print(type(env)) return env \ No newline at end of file diff --git a/env_wrapper.py b/env_wrapper.py index 9fc1327..0630cb4 100644 --- a/env_wrapper.py +++ b/env_wrapper.py @@ -1,8 +1,8 @@ import gymnasium as gym from gymnasium.core import Env -from gymnasium.wrappers import NormalizeObservation, NormalizeReward -import numpy as np -from gymnasium.spaces import Box +# Make sure these are here if not already +from numpy.random import default_rng +import simpy class ScaleQSimPyEnv(gym.RewardWrapper): @@ -13,12 +13,43 @@ def __init__(self, env: Env, scale: float): def reward(self, reward): reward *= self.scaling_factor return reward +class SerializableEnvWrapper(gym.Wrapper): + def __getattr__(self, name): + return getattr(self.env, name) + def __getstate__(self): + # Start with wrapper __dict__ + state = self.__dict__.copy() -class GymNormalizeObservation(NormalizeObservation): - def __init__(self, env: Env, *args, **kwargs): - super().__init__(env, *args, **kwargs) - self.observation_space = Box( - low=np.ones((self.env.obs_dim,)) * -np.inf, - high=np.ones((self.env.obs_dim,)) * np.inf, - ) + # Replace self.env with its safe state + if hasattr(self.env, "__getstate__"): + state["env_state"] = self.env.__getstate__() + else: + state["env_state"] = self.env.__dict__.copy() + + # Don't pickle the actual env object directly + if "env" in state: + del state["env"] + + # Debug: check for generators in wrapper state + for k, v in list(state.items()): + if hasattr(v, "__iter__") and not isinstance(v, (list, tuple, dict, str, bytes, np.ndarray)): + print(f"[WRAPPER-PICKLE] Removing generator-like object at key '{k}' ({type(v)})") + del state[k] + + # Preserve dataset path for reconstruction + state["_dataset_path"] = getattr(self.env, "dataset_path", None) + return state + + def __setstate__(self, state): + from gymenv_qsimpy import QSimPyEnv + dataset_path = state.pop("_dataset_path", None) + if not dataset_path: + raise ValueError("Missing dataset path for deserialization") + + new_env = QSimPyEnv(dataset=dataset_path) + if "env_state" in state: + new_env.__setstate__(state.pop("env_state")) + + super().__init__(new_env) + self.__dict__.update(state) diff --git a/gymenv_qsimpy.py b/gymenv_qsimpy.py index af5720e..5252298 100644 --- a/gymenv_qsimpy.py +++ b/gymenv_qsimpy.py @@ -54,6 +54,10 @@ def __init__( """ super().__init__() + if dataset is None: + raise ValueError("Dataset is not specified") + + self.dataset_path = dataset # OBSERVATION SPACE # Each observation is a dict of qtask_attributes and qnode_attributes @@ -79,37 +83,36 @@ def __init__( # Assuming the observation consists of [arrival_time, qubit_number, circuit_layers] for tasks # and [qubit_number, clops, next_available_time] for each node - task_obs_low = np.array([0, 0, 0, 0], dtype=np.float64) + task_obs_low = np.array([0, 0, 0, 0], dtype=np.float32) task_obs_high = np.array( - [max_time, max_qubits, max_layers, max_rescheduling_count], dtype=np.float64 + [max_time, max_qubits, max_layers, max_rescheduling_count], dtype=np.float32 ) - node_obs_low = np.array([0, 0, -1] * self.n_qnodes, dtype=np.float64) + node_obs_low = np.array([0, 0, -1] * self.n_qnodes, dtype=np.float32) node_obs_high = np.array( - [max_qubits, max_clops, max_time] * self.n_qnodes, dtype=np.float64 + [max_qubits, max_clops, max_time] * self.n_qnodes, dtype=np.float32 ) # Combine to form the complete observation space - obs_low = np.concatenate([task_obs_low, node_obs_low]).astype(np.float64) - obs_high = np.concatenate([task_obs_high, node_obs_high]).astype(np.float64) + obs_low = np.concatenate([task_obs_low, node_obs_low]).astype(np.float32) + obs_high = np.concatenate([task_obs_high, node_obs_high]).astype(np.float32) - self.observation_space = Box(low=obs_low, high=obs_high, dtype=np.float64) + self.observation_space = Box(low=obs_low, high=obs_high, dtype=np.float32) self.current_obs = None # ACTION SPACE self.action_space = Discrete(self.n_qnodes) # Load QTasks dataset - if dataset is None: - raise ValueError("Dataset is not specified") - self.qtask_dataset = Dataset(dataset) - self.rng = default_rng(seed=22) + self.qtask_dataset = Dataset(self.dataset_path) + self.seed = 22 + self.rng = default_rng(seed=self.seed) + # QSimPy environment self.qsp_env = simpy.Environment() self.setup_quantum_resources() # Round self.round = 1 - self.seed = 22 self.round_robin_index = 0 self.results = [] @@ -117,10 +120,47 @@ def __init__( self.rescheduling_time = 0.01 # Check if evaluation is set + if config is None: + config = {} self.evaluation = config.get("evaluation", False) self.policy = config.get("policy", "UnknownPolicy") + def __getstate__(self): + """ + This method prepares the object for serialization (pickling). + We remove all objects that cannot be pickled. + """ + state = self.__dict__.copy() + + # List of attributes to remove before pickling + unpicklable_attributes = [ + 'qsp_env', + 'broker', + 'qnodes', + 'rng', + 'qtask_dataset' + ] + + for attr in unpicklable_attributes: + if attr in state: + del state[attr] + + return state + + def __setstate__(self, state): + """ + This method restores the object after serialization. + We re-initialize the objects that we removed in __getstate__. + """ + self.__dict__.update(state) + + # Re-initialize the unpicklable attributes + self.qtask_dataset = Dataset(self.dataset_path) + self.rng = default_rng(seed=self.seed) + self.qsp_env = simpy.Environment() + self.setup_quantum_resources() + def _get_obs(self): """ Get the current observation of the environment. @@ -130,7 +170,7 @@ def _get_obs(self): """ # Get the current observation of quantum task if self.current_qtask is None: - self.qtask_obs = np.array([0, 0, 0, 0], dtype=np.float64) + self.qtask_obs = np.array([0, 0, 0, 0], dtype=np.float32) else: self.qtask_obs = np.array( [ @@ -139,7 +179,7 @@ def _get_obs(self): self.current_qtask.circuit_layers, self.current_qtask.rescheduling_count, ], - dtype=np.float64, + dtype=np.float32, ) # Get the current observation of quantum nodes @@ -151,14 +191,14 @@ def _get_obs(self): qnode.clops, qnode.next_available_time, ], - dtype=np.float64, + dtype=np.float32, ) self.qnode_obs.append(qnode_obs) # Flatten the qnode observations and concatenate with qtask observations - qnode_obs_flat = np.concatenate(self.qnode_obs).astype(np.float64) + qnode_obs_flat = np.concatenate(self.qnode_obs).astype(np.float32) self.current_obs = np.concatenate( - (self.qtask_obs, qnode_obs_flat), dtype=np.float64 + (self.qtask_obs, qnode_obs_flat), dtype=np.float32 ) return self.current_obs @@ -221,22 +261,22 @@ def generate_qtasks(self): self.round += 1 def submit_task_to_qnode(self, qtask, qnode_id=None): - reward = 0 if qnode_id is None: qnode_id = self.round_robin_index % self.n_qnodes self.round_robin_index += 1 + + # Check for task validity against the chosen node qtask, waiting_time, execution_time = self.broker.preprocess_qtask( qtask, self.qnodes[qnode_id] ) + if qtask.status == TaskStatus.ERROR: - # Apply large penalty to the reward if QTask constraints are not satisfied - # Beside, this task need to be rescheduled to another QNode until it can be executed - # Put this task back to the queue + # Handle infeasible scheduling qtask.status = TaskStatus.QUEUED qtask.QNode = None qtask.rescheduling_count += 1 - qtask.arrival_time += 1 - # Find the index to insert the qtask based on arrival_time + qtask.arrival_time = self.qsp_env.now + self.rescheduling_time + index = 0 while ( index < len(self.qtasks) @@ -244,29 +284,61 @@ def submit_task_to_qnode(self, qtask, qnode_id=None): ): index += 1 self.qtasks.insert(index, qtask) + + self.qsp_env.run(until=self.qsp_env.now + self.rescheduling_time) return -0.1, qtask.rescheduling_count - # Submit the qtask to the qnode following the action + + # If valid, schedule the task qtask_execution = self.broker.submit_qtask_to_qnode( qtask, self.qnodes[qnode_id] ) self.qsp_env.process(qtask_execution) - # Delay time is the time from initial arrival time to the time the task started to be placed in the QNode - delay_time = qtask.arrival_time - qtask.init_arrival_time - # print(f"Estimated waiting time: {waiting_time}") - # print(f"Estimated execution time: {execution_time}") + # --- START OF FIX --- + # Calculate all timing info BEFORE running the simulation + + # The task will start after the current time + its waiting time. + start_time = self.qsp_env.now + waiting_time + + # We can store this on the object now for logging purposes. + qtask.start_time = start_time + + # Calculate the exact time the simulation needs to run until. + completion_time = start_time + execution_time + + # Calculate the delay from the task's very first arrival. + delay_time = start_time - qtask.init_arrival_time + + # --- END OF FIX --- + + # NOW, run the simulation until this specific task is done + self.qsp_env.run(until=completion_time) + self.results.append({ 'qtask_id': qtask.id, 'qnode_id': qnode_id, 'waiting_time': waiting_time, 'execution_time': execution_time, - 'rescheduling_count': qtask.rescheduling_count, # Store the actual count from the task + 'rescheduling_count': qtask.rescheduling_count, }) - reward = delay_time + waiting_time + execution_time - return reward, qtask.rescheduling_count + + # The reward is based on the total time spent by the task in the system + total_time_in_system = delay_time + waiting_time + execution_time + + return total_time_in_system, qtask.rescheduling_count def reset(self, *, seed=None, options=None): - super().reset(seed=22) + super().reset(seed=seed) + if seed is not None: + self.seed = seed + + # Re-initialize the entire simulation environment + self.qsp_env = simpy.Environment() + self.rng = default_rng(seed=self.seed) + self.setup_quantum_resources() + self.results = [] + self.round = 1 + self.generate_qtasks() self.current_obs = self._get_obs().astype(np.float32) info = {} @@ -298,29 +370,36 @@ def collect_results(self): return summary def step(self, action): - # Submit the current qtask to the selected qnode - # action is qnode_id - # Intermediately reward is the inverse of completion time - # Sample Objective: Minimize the total completion time of all qtasks + # Submit the current qtask to the selected qnode and run the simulation + # The returned `time_reward` is the total time the task spent in the system time_reward, _ = self.submit_task_to_qnode( self.current_qtask, action ) - reward = 1/time_reward + + # A reward of -0.1 indicates a penalty for an invalid action + if time_reward == -0.1: + reward = -0.1 + else: + # The objective is to MINIMIZE completion time, so the reward should be inverse + # Add a small epsilon to avoid division by zero + reward = 1.0 / (time_reward + 1e-6) scheduled_qtask = self.current_qtask # Get the next observation - # Check if there are more qtasks, if yes, get the next qtask, otherwise set terminated to True if len(self.qtasks) > 0: self.current_qtask = self.qtasks.pop(0) + # Advance simulation time to the arrival of the next task if needed + if self.qsp_env.now < self.current_qtask.arrival_time: + self.qsp_env.run(until=self.current_qtask.arrival_time) terminated = False else: self.current_qtask = None terminated = True self.current_obs = self._get_obs() - - return self.current_obs, reward, terminated, False, {"scheduled_qtask": scheduled_qtask} + info = {"scheduled_qtask_id": scheduled_qtask.id} + return self.current_obs, reward, terminated, False, info def close(self): # If the evaluation is set, run the environment and export the results diff --git a/ray_train_dqn.py b/ray_train_dqn.py index dcc4b53..85dd3ef 100644 --- a/ray_train_dqn.py +++ b/ray_train_dqn.py @@ -4,9 +4,11 @@ from ray.tune.registry import register_env from env_creator import qsimpy_env_creator from ray.rllib.algorithms.dqn import DQNConfig +from ray.tune import RunConfig from ray.rllib.utils.framework import try_import_tf from ray.tune.analysis import ExperimentAnalysis import os +os.environ["RAY_TRAIN_V2_ENABLED"] = "1" tf1, tf, tfv = try_import_tf() parser = argparse.ArgumentParser() @@ -34,29 +36,21 @@ register_env("QSimPyEnv", qsimpy_env_creator) - replay_config = { - "type": "MultiAgentPrioritizedReplayBuffer", - "capacity": 60000, - "prioritized_replay_alpha": 0.5, - "prioritized_replay_beta": 0.5, - "prioritized_replay_eps": 3e-6, - } + # replay_config = { + # "type": "MultiAgentPrioritizedReplayBuffer", + # "capacity": 60000, + # "prioritized_replay_alpha": 0.5, + # "prioritized_replay_beta": 0.5, + # "prioritized_replay_eps": 3e-6, + # } config = ( DQNConfig() .framework(framework=args.framework) - .environment( - env="QSimPyEnv", - env_config={ - "obs_filter": "rescale_-1_1", - "reward_filter": None, - "dataset": "qdataset/qsimpyds_1000_sub_26.csv", - }, - ) + .environment(env="QSimPyEnv",env_config={"obs_filter": "rescale_-1_1","reward_filter": None,"dataset": "qdataset/qsimpyds_1000_sub_26.csv",},) .training( lr=tune.grid_search([0.01]), train_batch_size=tune.grid_search([78]), - replay_buffer_config=replay_config, num_atoms=tune.grid_search( [ 10 From cb575dcb6b7c9784001c6f6f61a5e8a5a796367d Mon Sep 17 00:00:00 2001 From: mopoa Date: Fri, 19 Sep 2025 15:45:03 +0330 Subject: [PATCH 5/8] WORKING_UPDATE2 --- env_wrapper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/env_wrapper.py b/env_wrapper.py index 0630cb4..07663e4 100644 --- a/env_wrapper.py +++ b/env_wrapper.py @@ -3,6 +3,7 @@ # Make sure these are here if not already from numpy.random import default_rng import simpy +import numpy as np class ScaleQSimPyEnv(gym.RewardWrapper): From 8f867c0f7f4fb2f29f8571ba83b1a84e5afb8625 Mon Sep 17 00:00:00 2001 From: mopoa Date: Sun, 21 Sep 2025 11:56:15 +0330 Subject: [PATCH 6/8] heuristic update with new env --- train_heuristics.py | 90 ++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/train_heuristics.py b/train_heuristics.py index a53f3e3..f879dc7 100644 --- a/train_heuristics.py +++ b/train_heuristics.py @@ -30,9 +30,10 @@ def run(self, control): self.results = [] # Reset the subset of QTasks - self.env.round = 1 + self.env.unwrapped.round = 1 - for _ in range(self.num_episodes): + # **FIX:** Use an episode counter to provide a unique seed for each episode + for episode_num in range(self.num_episodes): # Initialize the temporary array to store the results of the QTasks execution for each episode arr_temp = { @@ -41,10 +42,11 @@ def run(self, control): } terminated = False - # Reset the environment and setup the quantum resources - self.env.reset() - self.env.setup_quantum_resources() + # **FIX:** Pass the unique seed here to generate a new problem for each episode + self.env.reset(seed=episode_num) + self.env.unwrapped.setup_quantum_resources() self.rr_index = 0 + self.greedy_index = 0 while not terminated: # Get the action with the given control @@ -57,25 +59,27 @@ def run(self, control): elif control == "greedy_error": action = self.greedy_error(self.greedy_index) + # Save the task object before it gets processed by the step function + task_to_be_scheduled = self.env.unwrapped.current_qtask + obs, reward, terminated, done, info = self.env.step(action) - # If the QNode is busy or not satisfied, move to the next priority QNode - self.greedy_index += 1 + # If the action was invalid (e.g., node busy), increment the index for greedy strategies and try again + if reward < 0: # A reward of -0.1 indicates a penalty for an invalid action + self.greedy_index += 1 + + # If the action was valid and the task was scheduled if reward > 0: - """Get the results of the QTask execution - - Values: - - Total Completion Time: waiting_time + execution_time - - Rescheduling Count: rescheduling_count - """ - # Reset priority index of Greedy solution if QTasks are satisfied + # Reset priority index of Greedy solution for the next task self.greedy_index = 0 - arr_temp["total_completion_time"] += info["scheduled_qtask"].waiting_time + info["scheduled_qtask"].execution_time - arr_temp["rescheduling_count"] += info["scheduled_qtask"].rescheduling_count + # Use the saved task object to access its properties + arr_temp["total_completion_time"] += task_to_be_scheduled.waiting_time + task_to_be_scheduled.execution_time + arr_temp["rescheduling_count"] += task_to_be_scheduled.rescheduling_count + sys.stdout.write("\033[F\033[K") - print(f"progress: {len(self.results)}%") - self.env.qsp_env.run() + print(f"[{control}] progress: {episode_num + 1}/{self.num_episodes}") + self.env.unwrapped.qsp_env.run() # Final results of the episode self.results.append(arr_temp) @@ -84,8 +88,10 @@ def run(self, control): def greedy(self, greedy_index): # Sort the QNodes based on the next available time (or waiting time) and select the QNode with the smallest waiting time - greedy_strategy = sorted(self.env.qnodes, key=lambda x: x.next_available_time) - return self.env.qnodes.index(greedy_strategy[greedy_index]) + greedy_strategy = sorted(self.env.unwrapped.qnodes, key=lambda x: x.next_available_time) + # Prevent index error if all nodes are invalid + safe_index = min(greedy_index, len(greedy_strategy) - 1) + return self.env.unwrapped.qnodes.index(greedy_strategy[safe_index]) def random(self): # Randomly select a QNode @@ -94,16 +100,16 @@ def random(self): def round_robin(self): # Select the QNode based on the Round Robin index - action = self.rr_index % self.env.n_qnodes + action = self.rr_index % self.env.unwrapped.n_qnodes self.rr_index += 1 return action def greedy_error(self, greedy_index, g_error="Readout_assignment_error"): - # Sort the QNodes based on the next available time (or waiting time) and select the QNode with the - # smallest waiting time and smallest error (default is readout_error) in the qnode - - greedy_strategy = sorted(self.env.qnodes, key=lambda x: (x.next_available_time, x.error[g_error])) - return self.env.qnodes.index(greedy_strategy[greedy_index]) + # Sort the QNodes based on the next available time and then by error + greedy_strategy = sorted(self.env.unwrapped.qnodes, key=lambda x: (x.next_available_time, x.error[g_error])) + # Prevent index error if all nodes are invalid + safe_index = min(greedy_index, len(greedy_strategy) - 1) + return self.env.unwrapped.qnodes.index(greedy_strategy[safe_index]) def _save_to_csv(self, control) -> None: """ @@ -132,6 +138,7 @@ def _plot_results(self, paths) -> None: """ Plot the results of the episodes. """ + plt.figure(figsize=(12, 7)) for path in paths: df1 = pd.read_csv(path['path']) @@ -141,7 +148,9 @@ def _plot_results(self, paths) -> None: plt.ylabel('Total Completion Time') plt.xlabel('Evaluation Episode') - plt.legend(loc=2) + plt.title('Heuristic Method Performance Comparison') + plt.legend(loc='best') + plt.grid(True) plt.gca().xaxis.set_major_locator(mticker.MultipleLocator(10)) plt.show() @@ -149,10 +158,11 @@ def _summarize_results(self, values, label) -> None: """ Summarize the results of the episodes. """ - print("Results Summary for" + label + "solution:") + print("\n--- Results Summary for " + label + " solution ---") print(f"Number of Episodes: {self.num_episodes}") - print(f"Total Completion Time: {sum(values['Total Completion Time'])}") - print(f"Average Rescheduling Count: {sum(values['Rescheduling Count']) / self.num_episodes}") + print(f"Average Total Completion Time: {sum(values['Total Completion Time']) / self.num_episodes:.2f}") + print(f"Average Rescheduling Count: {sum(values['Rescheduling Count']) / self.num_episodes:.2f}") + print("------------------------------------------") if __name__ == "__main__": @@ -170,36 +180,34 @@ def _summarize_results(self, values, label) -> None: heuristics = HeuristicSolutions(env, num_episodes=100) methods = ['greedy','random','round_robin','greedy_error'] processes = [Process(target=heuristics.run , args=(m,)) for m in methods] - for i in range(len(methods)) : processes[i].start() - for i in range(len(methods)) : processes[i].join() + for p in processes: + p.start() + for p in processes: + p.join() print("All Processes are done!!") - # heuristics.run("greedy") - # heuristics.run("random") - # heuristics.run("round_robin") - # heuristics.run("greedy_error") # Plot the results paths = [ { - "label": "random", + "label": "Random", "path": "./results/heuristics/random.csv", "color": "red" }, { - "label": "round robin", + "label": "Round Robin", "path": "./results/heuristics/round_robin.csv", "color": "blue" }, { - "label": "greedy", + "label": "Greedy", "path": "./results/heuristics/greedy.csv", "color": "black" }, { - "label": "greedy_error", + "label": "Greedy + Error", "path": "./results/heuristics/greedy_error.csv", "color": "green" }, ] - heuristics._plot_results(paths) + heuristics._plot_results(paths) \ No newline at end of file From ea194ce0c978452ab553afaff6c4befdb05a2a1d Mon Sep 17 00:00:00 2001 From: mopoa Date: Sun, 21 Sep 2025 22:17:11 +0330 Subject: [PATCH 7/8] heuristics new methods --- env_creator.py | 2 +- gymenv_qsimpy.py | 10 +- results/heuristics/greedy.csv | 200 ++++++++--------- results/heuristics/greedy_error.csv | 200 ++++++++--------- results/heuristics/random.csv | 200 ++++++++--------- results/heuristics/round_robin.csv | 200 ++++++++--------- train_heuristics.py | 321 +++++++++++++++++++--------- zolution/TASK.jpg | Bin 0 -> 28029 bytes zolution/optimization_solution.txt | 78 +++++++ zolution/resultheuristic.png | Bin 0 -> 98191 bytes 10 files changed, 710 insertions(+), 501 deletions(-) create mode 100644 zolution/TASK.jpg create mode 100644 zolution/optimization_solution.txt create mode 100644 zolution/resultheuristic.png diff --git a/env_creator.py b/env_creator.py index bf0ab97..2ab1e51 100644 --- a/env_creator.py +++ b/env_creator.py @@ -30,5 +30,5 @@ def qsimpy_env_creator(env_config): if reward_filter == "scale_2x": env = ScaleQSimPyEnv(env, scale=env_config.pop("reward_scale", 2)) - for i in range(10) : print(type(env)) + # for i in range(10) : print(type(env)) return env \ No newline at end of file diff --git a/gymenv_qsimpy.py b/gymenv_qsimpy.py index 5252298..0f75d47 100644 --- a/gymenv_qsimpy.py +++ b/gymenv_qsimpy.py @@ -67,6 +67,7 @@ def __init__( self.n_qnodes = 5 # number of qnodes self.qtasks = [] self.qnodes = [] + self.serviced_qtasks = [] self.mode = mode self.obs_dim = 4 + self.n_qnodes * 3 self.observation_space = Box( @@ -217,6 +218,10 @@ def setup_quantum_resources(self): for qid, qname in zip(qnode_ids, qnode_names) ] + # Manually assign the name attribute to each node after creation + for node, name in zip(self.qnodes, qnode_names): + node.name = name + # Create a Broker self.broker = Broker(self.qsp_env, self.qnodes, self.mode) @@ -322,6 +327,8 @@ def submit_task_to_qnode(self, qtask, qnode_id=None): 'rescheduling_count': qtask.rescheduling_count, }) + self.serviced_qtasks.append(qtask) + # The reward is based on the total time spent by the task in the system total_time_in_system = delay_time + waiting_time + execution_time @@ -338,7 +345,8 @@ def reset(self, *, seed=None, options=None): self.setup_quantum_resources() self.results = [] self.round = 1 - + self.serviced_qtasks = [] + self.generate_qtasks() self.current_obs = self._get_obs().astype(np.float32) info = {} diff --git a/results/heuristics/greedy.csv b/results/heuristics/greedy.csv index 3b19e5e..7115573 100644 --- a/results/heuristics/greedy.csv +++ b/results/heuristics/greedy.csv @@ -1,101 +1,101 @@ Episode,Total Completion Time,Rescheduling Count -0,774.4230420475817,40.0 -1,1046.894424897719,42.0 -2,617.9205737688227,40.0 -3,628.8109224991855,40.0 -4,866.5606607725742,42.0 -5,566.5663152799716,36.0 -6,413.6463392302391,30.0 -7,432.2598716991536,32.0 -8,870.3762464998516,41.0 -9,1394.6824482677005,42.0 -10,363.90939944019135,39.0 -11,383.7768448815786,33.0 -12,207.1562787454552,35.0 -13,621.3609037155244,35.0 -14,742.9834560198984,36.0 -15,408.37357491369073,29.0 -16,849.3653276907853,40.0 -17,589.6526842487319,39.0 -18,690.1527352313494,38.0 -19,463.1828397210162,44.0 -20,749.1483089017328,37.0 -21,361.10023576100224,33.0 -22,1020.6336747898247,40.0 -23,643.4919808072126,39.0 -24,678.9492887209697,36.0 -25,704.0030903378286,40.0 -26,236.71913086329505,24.0 -27,868.0363015343289,40.0 -28,514.4224902263933,35.0 -29,1029.4922803886213,42.0 -30,886.7245346776365,37.0 -31,586.3764599582873,41.0 -32,433.24367449188094,32.0 -33,653.1261897262499,36.0 -34,554.3090769693335,42.0 -35,700.4555073920585,37.0 -36,601.7057329653607,38.0 -37,670.5812418983837,44.0 -38,771.29270222627,34.0 -39,558.4195175017535,40.0 -40,532.6560439087277,38.0 -41,599.5196239369212,44.0 -42,536.9127082928047,38.0 -43,727.4146780551054,40.0 -44,375.8560508023986,35.0 -45,566.307642637826,37.0 -46,460.37506666810236,39.0 -47,757.2286153476097,41.0 -48,545.5224263252145,32.0 -49,478.29268766411326,42.0 -50,435.43733240245353,38.0 -51,695.6963699855635,39.0 -52,482.25652324277115,37.0 -53,869.7229706811498,41.0 -54,546.1983303906775,31.0 -55,590.9020429390708,35.0 -56,755.3380698294844,40.0 -57,558.4616943255035,40.0 -58,545.7684111909076,40.0 -59,425.70812736455537,37.0 -60,633.0101678477301,35.0 -61,521.8836754508253,36.0 -62,973.8842211028855,43.0 -63,412.82137516049215,38.0 -64,987.7760875697948,40.0 -65,642.5279610549509,39.0 -66,582.1721791618904,36.0 -67,693.9500035705355,40.0 -68,789.7683292375004,38.0 -69,684.3098796725943,40.0 -70,604.3977524815559,36.0 -71,802.168098151363,41.0 -72,788.5206318256928,42.0 -73,676.1757941145282,34.0 -74,589.1742946893258,38.0 -75,787.8254076771084,44.0 -76,589.0176430744142,38.0 -77,769.168050375966,42.0 -78,739.4541400399085,40.0 -79,597.4687583949419,33.0 -80,446.0454398494521,32.0 -81,507.43657309680856,31.0 -82,509.46519499947544,31.0 -83,477.6576370957176,39.0 -84,448.7200313033012,38.0 -85,959.3483665188473,44.0 -86,552.6945242207725,30.0 -87,832.3409587334892,40.0 -88,587.9273806639311,35.0 -89,679.4131679478429,37.0 -90,393.8545712065559,31.0 -91,762.0365058522186,38.0 -92,447.8208740424661,38.0 -93,915.649490044282,40.0 -94,768.9448839386108,42.0 -95,388.82369455317746,33.0 -96,1251.7773158818782,42.0 -97,739.013409053475,41.0 -98,760.3428642461873,43.0 -99,789.5407058575811,42.0 +0,1183.9459122412904,36.0 +1,1304.1060486889678,38.0 +2,1107.3483841461803,38.0 +3,1237.9392352300667,38.0 +4,1236.9295710178753,41.0 +5,1210.8028734110198,36.0 +6,1043.9534820251167,40.0 +7,1156.492801015281,36.0 +8,1220.9602955695482,42.0 +9,1011.3446698887095,37.0 +10,1081.2775353421061,39.0 +11,1244.319998800302,38.0 +12,1218.2735617508893,38.0 +13,1019.388821666389,37.0 +14,1229.8966170481547,39.0 +15,1093.6212427601924,38.0 +16,1231.423899488196,38.0 +17,1367.5884718464686,39.0 +18,1120.9125786460893,38.0 +19,1394.0235256291312,41.0 +20,1298.3253944598105,38.0 +21,988.378698479236,39.0 +22,1236.2641099207906,38.0 +23,1049.1392418742864,39.0 +24,1237.766463115403,38.0 +25,1169.4162655674684,38.0 +26,1425.5167191375926,38.0 +27,1190.8823215669206,37.0 +28,1194.590567863168,37.0 +29,1110.6357167097287,41.0 +30,1231.5172977589273,38.0 +31,1048.4470859354412,39.0 +32,1192.7609613262216,41.0 +33,1282.3116189327266,39.0 +34,1036.2638878508128,38.0 +35,1225.198734340374,39.0 +36,1330.3044485649173,38.0 +37,1198.3259132522317,39.0 +38,1271.4388610294975,39.0 +39,1240.5114604013022,38.0 +40,1141.5616815790954,37.0 +41,1274.9352952524102,35.0 +42,1121.9371921773936,37.0 +43,1195.0337454219111,41.0 +44,1242.812993445969,40.0 +45,1283.902709950512,38.0 +46,1241.8853796051471,39.0 +47,1040.5459565277777,39.0 +48,1276.0220852937023,38.0 +49,1181.8744537609898,36.0 +50,1239.2056215332216,38.0 +51,1102.8949106096657,36.0 +52,953.7059610662435,40.0 +53,1101.4305486729659,36.0 +54,1070.445474088991,39.0 +55,1214.79866104364,38.0 +56,1020.4426571535101,37.0 +57,1349.0980442539358,39.0 +58,1133.8641803805442,38.0 +59,1282.639861556527,42.0 +60,1181.2986079255668,41.0 +61,1145.9037738151753,41.0 +62,1240.06598238621,36.0 +63,1189.4294459065386,39.0 +64,1090.9949717103702,36.0 +65,1327.2917867095198,39.0 +66,1227.4314309062956,38.0 +67,1301.3005820184655,39.0 +68,1153.8009942751514,38.0 +69,1111.8386284684382,38.0 +70,1088.046739061963,42.0 +71,1123.7784870438327,38.0 +72,1041.5766966554759,40.0 +73,1066.0858238109768,40.0 +74,1283.3385153928568,41.0 +75,973.6595792404268,37.0 +76,1213.365629465177,36.0 +77,1348.563805964419,38.0 +78,1272.2176877603745,39.0 +79,1234.2354816808408,35.0 +80,1107.6129207490808,39.0 +81,1181.150685564418,38.0 +82,1292.1929208929669,38.0 +83,1319.2524725250626,39.0 +84,1314.4200041548559,38.0 +85,1227.2961509144877,38.0 +86,1150.4419566864112,38.0 +87,1073.774883730797,39.0 +88,1152.4827565837513,38.0 +89,1167.1131917720652,38.0 +90,1223.875985559418,39.0 +91,1389.297687318999,37.0 +92,1318.553506466468,38.0 +93,1114.2891554425914,38.0 +94,1306.2362995090953,38.0 +95,1216.249038236079,37.0 +96,938.5699404450673,37.0 +97,1232.1592333680205,38.0 +98,1287.1247279794693,39.0 +99,1208.4424941191712,42.0 diff --git a/results/heuristics/greedy_error.csv b/results/heuristics/greedy_error.csv index 98848a4..4056309 100644 --- a/results/heuristics/greedy_error.csv +++ b/results/heuristics/greedy_error.csv @@ -1,101 +1,101 @@ Episode,Total Completion Time,Rescheduling Count -0,779.286564033785,44.0 -1,1018.0907645941475,46.0 -2,641.8455081869836,44.0 -3,654.0831900588066,44.0 -4,871.1009895371011,46.0 -5,585.3419575893722,40.0 -6,446.8945558944891,35.0 -7,512.7857438402183,36.0 -8,870.0392874462106,45.0 -9,1403.2538843569118,46.0 -10,437.20049371329264,43.0 -11,387.3112745833579,37.0 -12,241.9880555126875,40.0 -13,626.9781166282103,39.0 -14,780.902382522772,40.0 -15,388.4511046105547,35.0 -16,827.7077435577246,44.0 -17,607.3581004546566,43.0 -18,700.7635993222689,42.0 -19,499.64671161102183,48.0 -20,755.1151848860904,37.0 -21,395.14827467242446,37.0 -22,1118.8852805272445,44.0 -23,672.2494591832836,43.0 -24,752.6005621924559,40.0 -25,721.8238032533495,44.0 -26,207.0930613935666,28.0 -27,888.658573558916,44.0 -28,534.4488956052584,39.0 -29,1005.5085728583823,43.0 -30,853.3132124534151,41.0 -31,590.8656874378183,45.0 -32,461.01304465604215,36.0 -33,686.935225951273,40.0 -34,577.5721509951466,46.0 -35,716.722166899953,41.0 -36,625.5229764371421,41.0 -37,615.3195559790382,48.0 -38,780.3194866897076,38.0 -39,594.9541520086445,44.0 -40,561.3443611413669,43.0 -41,661.7754295462144,48.0 -42,571.6179140077627,42.0 -43,737.876597753784,44.0 -44,398.5770308682531,39.0 -45,593.1565609649705,41.0 -46,448.31888197741904,43.0 -47,739.4550793811899,45.0 -48,566.6025067912151,36.0 -49,488.08591091471266,46.0 -50,473.32301622092916,41.0 -51,702.8283220644104,43.0 -52,501.7041333591779,41.0 -53,859.9557336531625,45.0 -54,572.9886504975027,34.0 -55,682.6790300121812,39.0 -56,784.8824768279756,44.0 -57,524.2425649438379,44.0 -58,560.7080082720844,41.0 -59,470.0018740168153,41.0 -60,685.8348449770591,39.0 -61,578.3072927716473,41.0 -62,1037.7674743484838,47.0 -63,363.07834646054357,41.0 -64,975.0234557794759,44.0 -65,645.9724131814359,43.0 -66,572.6235504259654,37.0 -67,703.0491048629965,44.0 -68,816.9584956357872,42.0 -69,645.0645671546602,44.0 -70,601.470562470287,36.0 -71,792.2956085695879,45.0 -72,794.2921778200525,46.0 -73,687.8876958511382,38.0 -74,563.7197154668082,43.0 -75,810.3360229023112,48.0 -76,630.9707744234905,42.0 -77,808.783449981612,46.0 -78,760.8511106964423,44.0 -79,614.4434092193461,39.0 -80,476.1463679302302,36.0 -81,547.9441818033677,35.0 -82,545.6914809418145,35.0 -83,485.7904843422369,39.0 -84,450.62171141799803,42.0 -85,1073.4248717263085,48.0 -86,551.0077594549593,34.0 -87,825.3505545480989,44.0 -88,610.0023367103439,39.0 -89,697.8224633469039,41.0 -90,412.86652903623803,35.0 -91,769.2821875828371,42.0 -92,430.0895171689559,41.0 -93,955.1218764261479,44.0 -94,774.9226519278552,46.0 -95,410.0365030939497,37.0 -96,1256.3691795545785,46.0 -97,767.2365327297308,45.0 -98,752.0432471902363,47.0 -99,798.6604685050595,46.0 +0,1239.048764954939,39.0 +1,1447.3809102195498,40.0 +2,1357.8592302626796,41.0 +3,1426.5984717667798,40.0 +4,1394.9996964120105,40.0 +5,1412.4067564950926,40.0 +6,1191.8641597521364,39.0 +7,1369.5599085838317,41.0 +8,1339.3670167557111,44.0 +9,1316.256617779292,40.0 +10,1212.947162058655,40.0 +11,1315.5206810147536,39.0 +12,1246.0090195324747,41.0 +13,1366.1959387382353,40.0 +14,1478.5206967556799,41.0 +15,1355.715657016669,40.0 +16,1398.573522782949,41.0 +17,1394.897703598718,41.0 +18,1241.8491035509005,40.0 +19,1451.7677670922074,41.0 +20,1587.4008554661368,39.0 +21,1376.4154484092592,41.0 +22,1368.617729101173,39.0 +23,1407.958307495498,40.0 +24,1398.8189078951605,40.0 +25,1350.8575797398626,41.0 +26,1392.9980640182523,40.0 +27,1391.7148493963932,41.0 +28,1212.3957010955828,35.0 +29,1410.6336057756723,40.0 +30,1290.5416794481623,39.0 +31,1318.9594541601798,40.0 +32,1431.2819413412565,40.0 +33,1448.984343305557,40.0 +34,1370.4671158191245,40.0 +35,1278.436882343706,38.0 +36,1441.024057680508,40.0 +37,1519.152766779766,41.0 +38,1332.764898867378,40.0 +39,1378.6588217403244,40.0 +40,1405.4835611885142,41.0 +41,1408.1875283395673,40.0 +42,1377.5221767896976,40.0 +43,1405.6932855039502,40.0 +44,1502.6204558223353,40.0 +45,1292.0080638511467,41.0 +46,1461.478976682054,40.0 +47,1173.0722514624342,40.0 +48,1458.11592944274,40.0 +49,1437.109101365366,40.0 +50,1348.263786161681,41.0 +51,1245.4731287417042,41.0 +52,1207.9527096172408,38.0 +53,1370.9602446541264,40.0 +54,1494.6075327702733,40.0 +55,1409.7283273069293,40.0 +56,1382.592160415308,41.0 +57,1417.6208083973188,40.0 +58,1270.4401160749385,41.0 +59,1441.9791558577772,44.0 +60,1360.0366106276126,40.0 +61,1342.5820858907832,40.0 +62,1391.6678384105055,40.0 +63,1374.657497027954,44.0 +64,1414.132261469257,41.0 +65,1239.539215641884,39.0 +66,1287.5161549173463,40.0 +67,1124.2196070761331,44.0 +68,1474.8428768126796,41.0 +69,1111.0591749111454,43.0 +70,1294.0883411166772,44.0 +71,1385.9202239156766,39.0 +72,1263.1937058490112,39.0 +73,1571.2648734549819,40.0 +74,1346.4777982177188,40.0 +75,1341.1920443637373,40.0 +76,1307.8279986720497,41.0 +77,1442.3777391602084,40.0 +78,1109.553424136137,44.0 +79,1405.6549117074155,41.0 +80,1049.6954729488489,40.0 +81,1436.421981938819,40.0 +82,1168.6795780273285,41.0 +83,1411.9838896494286,40.0 +84,1494.123101631842,40.0 +85,1368.5519941081814,41.0 +86,1219.095679234422,39.0 +87,1411.0638647887636,41.0 +88,1337.403006103293,41.0 +89,1375.6374114372045,41.0 +90,1376.9316550241626,40.0 +91,1584.2203210207706,41.0 +92,1298.028778210999,41.0 +93,1318.8314543537363,41.0 +94,1364.6143698879666,39.0 +95,1424.4839910707544,40.0 +96,1435.5224124829674,40.0 +97,1295.3617411987918,41.0 +98,1309.8264641208705,39.0 +99,1470.2992080648744,41.0 diff --git a/results/heuristics/random.csv b/results/heuristics/random.csv index 5965701..034f207 100644 --- a/results/heuristics/random.csv +++ b/results/heuristics/random.csv @@ -1,101 +1,101 @@ Episode,Total Completion Time,Rescheduling Count -0,1347.0420317101161,15.0 -1,2134.615473591639,21.0 -2,931.6157167605069,11.0 -3,1149.997513162218,14.0 -4,1391.6838692913027,22.0 -5,639.2270410963438,8.0 -6,796.4860315595515,17.0 -7,1187.889997023277,10.0 -8,1227.0110787994006,7.0 -9,2528.731160124443,18.0 -10,625.776928852375,12.0 -11,583.9825487811677,10.0 -12,625.3597619992973,8.0 -13,1933.2817353580504,12.0 -14,1455.2642503744746,15.0 -15,547.954802710524,10.0 -16,1300.6682634247059,12.0 -17,789.7169707164147,11.0 -18,1884.4023780452133,12.0 -19,878.7414213461481,11.0 -20,1549.0828207597203,16.0 -21,520.3818429392153,11.0 -22,1196.4580030886875,19.0 -23,1094.760111361848,11.0 -24,1787.5626571175383,9.0 -25,2377.709538588765,14.0 -26,465.5393532371849,6.0 -27,1331.6933816422634,21.0 -28,848.3190501213164,8.0 -29,1317.1148989824885,12.0 -30,1440.8638159106113,24.0 -31,1422.63266536302,20.0 -32,1230.1264317323712,14.0 -33,1172.3158427171247,14.0 -34,600.6742274315427,22.0 -35,1137.5399491945614,17.0 -36,849.0172086392379,11.0 -37,707.8641183656605,16.0 -38,1131.2976618797368,19.0 -39,708.5972525763398,12.0 -40,777.3619729044475,13.0 -41,1062.9363573557137,20.0 -42,964.4460485745744,17.0 -43,982.303283973371,10.0 -44,674.477035347528,12.0 -45,1003.2072990075158,2.0 -46,974.0452370191756,21.0 -47,936.4548728614423,14.0 -48,951.8152151127535,26.0 -49,580.3156461007073,11.0 -50,846.9098703835471,16.0 -51,1804.7971919066913,7.0 -52,763.0649601246339,13.0 -53,1642.9519199126821,12.0 -54,997.6082886834663,21.0 -55,1015.6033879965863,18.0 -56,1281.138227784497,9.0 -57,899.7454975314889,8.0 -58,1004.1053884234485,11.0 -59,825.1421628577752,17.0 -60,1113.8294817673973,12.0 -61,1358.0867842858531,17.0 -62,1823.6408052985335,9.0 -63,702.3224742703404,5.0 -64,1526.5970898020755,12.0 -65,895.5619896043671,12.0 -66,1429.8304833933523,8.0 -67,1131.8710432049884,19.0 -68,870.2476880633367,19.0 -69,995.7250401435597,16.0 -70,1115.0837382107547,9.0 -71,1180.8408955445807,11.0 -72,1750.1793239157237,8.0 -73,779.3600443538534,8.0 -74,1149.045050708336,10.0 -75,948.9796049739532,5.0 -76,908.0352870548267,14.0 -77,879.4513685802084,14.0 -78,1362.5922868228806,12.0 -79,834.5922367523832,13.0 -80,745.6078788119031,6.0 -81,2043.474233659995,12.0 -82,728.9880108313126,8.0 -83,854.6309431034314,11.0 -84,551.1450535877735,18.0 -85,1662.035399053742,24.0 -86,1260.3175156009072,4.0 -87,1270.4618396547992,11.0 -88,753.2788098899683,17.0 -89,1818.749886676378,8.0 -90,1609.1234927051564,9.0 -91,1256.806940443047,19.0 -92,1288.5197175598275,9.0 -93,1513.908532729961,17.0 -94,858.4830049034177,17.0 -95,672.8613072154333,23.0 -96,2192.8170253518483,17.0 -97,1293.313628335685,9.0 -98,1730.8973118938827,11.0 -99,1382.6731211841375,19.0 +0,5198.593881514102,13.0 +1,5613.302968998986,14.0 +2,4003.990819664853,19.0 +3,8444.450131784446,9.0 +4,4286.1220704825155,12.0 +5,8031.450448715791,10.0 +6,6789.781269221228,11.0 +7,3543.4557720357516,15.0 +8,12273.37572409921,9.0 +9,9646.92642413784,11.0 +10,8813.460771810749,11.0 +11,4553.869421968707,16.0 +12,7904.990971970607,11.0 +13,15807.862130028756,9.0 +14,3380.1283729960246,22.0 +15,4837.782106291301,8.0 +16,3544.7102284757507,22.0 +17,6817.367764301595,12.0 +18,9037.215121279707,9.0 +19,6416.54946419231,19.0 +20,7014.375858135391,13.0 +21,8822.041678422705,7.0 +22,4991.453208830219,9.0 +23,4483.4764827903355,10.0 +24,4005.296517933301,14.0 +25,2277.2058361203003,21.0 +26,4383.8941244667685,18.0 +27,3148.304079331725,11.0 +28,4843.388450419759,11.0 +29,4354.150660936775,22.0 +30,5197.680892335768,8.0 +31,5391.891422966844,16.0 +32,3768.2256284565347,16.0 +33,9351.238154931527,15.0 +34,5471.762399949438,10.0 +35,6075.139230340897,10.0 +36,5720.0022304127,17.0 +37,5863.970166233917,7.0 +38,3892.8799395691417,7.0 +39,8681.737864246154,10.0 +40,5266.070835987855,21.0 +41,4125.918679463659,11.0 +42,2073.4457855385367,20.0 +43,6934.139143525072,10.0 +44,4054.2488036486807,7.0 +45,5651.354335859565,12.0 +46,3814.7668949773306,17.0 +47,6966.617077933323,7.0 +48,8215.29856207512,10.0 +49,8451.562759253464,5.0 +50,9009.005066346415,15.0 +51,3508.626605506074,14.0 +52,6709.753156042707,14.0 +53,4076.025786425259,10.0 +54,5463.946602458646,13.0 +55,9497.415998368384,13.0 +56,3597.1930906058383,15.0 +57,3131.0649049685776,15.0 +58,8327.734181098755,6.0 +59,6004.484850597683,11.0 +60,4228.066800751873,6.0 +61,5239.487452821901,6.0 +62,7177.82395018398,16.0 +63,6525.6778982239575,14.0 +64,4990.597348920271,14.0 +65,3736.1051504266793,12.0 +66,4841.75723597414,6.0 +67,8584.249235020428,17.0 +68,4066.003577074813,17.0 +69,3398.213883587471,10.0 +70,5938.105106204257,9.0 +71,4856.153969281786,11.0 +72,4147.926325279979,17.0 +73,3173.035681716114,14.0 +74,4745.548226057148,13.0 +75,4776.743268000405,21.0 +76,4607.533759486629,14.0 +77,11686.28389430349,9.0 +78,4377.16607447434,20.0 +79,5250.1168560443675,13.0 +80,7136.780606628455,11.0 +81,5395.92032519524,11.0 +82,5548.126131897136,13.0 +83,4505.617100369699,11.0 +84,4187.86187803539,19.0 +85,3963.251725091569,14.0 +86,5332.233057462485,16.0 +87,5681.587673058929,17.0 +88,5728.9023137522245,3.0 +89,7922.29047185589,5.0 +90,5235.859484687564,16.0 +91,8972.26163422719,4.0 +92,4345.741343872391,10.0 +93,1644.578171259856,34.0 +94,2971.0588736881214,22.0 +95,17173.949128379267,5.0 +96,2659.3054093785963,18.0 +97,4269.8547739742835,13.0 +98,8678.250330361365,23.0 +99,5422.7976721694295,8.0 diff --git a/results/heuristics/round_robin.csv b/results/heuristics/round_robin.csv index d4b26d7..0555ae3 100644 --- a/results/heuristics/round_robin.csv +++ b/results/heuristics/round_robin.csv @@ -1,101 +1,101 @@ Episode,Total Completion Time,Rescheduling Count -0,1105.376982535404,12.0 -1,1487.6684240714526,14.0 -2,1003.9454052829486,11.0 -3,1038.8745393466731,12.0 -4,1299.1035864225507,14.0 -5,994.9267037608945,12.0 -6,642.1537110087992,8.0 -7,737.1246372992813,9.0 -8,1266.6174705125034,12.0 -9,1934.2820720795903,14.0 -10,652.6149793987391,10.0 -11,636.0353949093793,11.0 -12,789.8981706285971,12.0 -13,1040.7566042338756,12.0 -14,1215.5884795218835,12.0 -15,704.3389460643133,11.0 -16,1314.7420651045759,13.0 -17,1234.2307452908872,11.0 -18,1096.6470150406103,13.0 -19,754.8117563731232,16.0 -20,1167.8155382243372,13.0 -21,789.3921964899594,12.0 -22,1682.338749833467,16.0 -23,1079.7550885300163,12.0 -24,1237.240277197955,11.0 -25,1272.1298386988783,16.0 -26,554.4603024494769,10.0 -27,1338.7673269998438,13.0 -28,651.9116917076187,9.0 -29,1537.2516371550323,14.0 -30,1060.3157854764336,10.0 -31,830.8000676433368,12.0 -32,962.2197014223709,9.0 -33,934.7430027038413,11.0 -34,948.5813207350654,13.0 -35,1227.08337069528,12.0 -36,1005.2195554656358,11.0 -37,953.2724846087079,13.0 -38,1252.496288361309,14.0 -39,976.9133051419012,13.0 -40,1046.7601464907355,11.0 -41,850.3341641409071,14.0 -42,958.3598646810218,11.0 -43,893.7463361581605,9.0 -44,927.9703627988202,12.0 -45,1006.4689390288339,8.0 -46,768.5525667533906,13.0 -47,1182.2418362192568,16.0 -48,961.7663931039309,12.0 -49,1025.2304870150117,11.0 -50,899.5448370077687,11.0 -51,1167.0770991997883,11.0 -52,890.0898107826142,10.0 -53,1364.073845043698,11.0 -54,916.2213644557462,6.0 -55,956.7117000171296,11.0 -56,1181.8675687766424,12.0 -57,1021.2264185846531,12.0 -58,1075.0286915604843,12.0 -59,690.3136465964394,14.0 -60,1154.4542019049188,11.0 -61,956.843633572331,9.0 -62,1268.1779608738075,13.0 -63,724.7248347397484,14.0 -64,1194.0392870139685,13.0 -65,1274.136163978858,11.0 -66,995.482429491637,10.0 -67,1034.443320722132,11.0 -68,1046.9285281646203,10.0 -69,960.9734191296022,9.0 -70,1141.5371305704841,11.0 -71,1173.980757277937,12.0 -72,1014.9297784836522,13.0 -73,928.5376868243017,12.0 -74,1239.187034726945,11.0 -75,1145.5754732057958,13.0 -76,1070.0248707854594,12.0 -77,1149.8336527963938,16.0 -78,1213.4202684400466,16.0 -79,1122.8360064094782,12.0 -80,797.2862170541603,8.0 -81,1187.712529888232,13.0 -82,1225.9002452063523,11.0 -83,756.29929972232,12.0 -84,691.1052330532966,7.0 -85,1249.0359355328233,12.0 -86,981.310828836232,10.0 -87,1243.2875428842135,13.0 -88,814.6823990524504,13.0 -89,1197.5476126673075,13.0 -90,712.9938393102277,7.0 -91,1237.5586641138707,11.0 -92,949.349873557107,14.0 -93,1435.8744891001809,12.0 -94,1223.0608857483298,12.0 -95,600.5653083914607,10.0 -96,1424.3967832513704,14.0 -97,1068.4438512943414,14.0 -98,1269.3237905789406,13.0 -99,1079.0484036200105,13.0 +0,6506.023895405447,16.0 +1,6610.537996610873,16.0 +2,6846.659553690184,16.0 +3,6758.504057494352,16.0 +4,6935.5544384370705,13.0 +5,7034.135898475587,16.0 +6,6630.794734678966,16.0 +7,6970.078715556613,16.0 +8,7112.18140915512,16.0 +9,6235.4468231614255,13.0 +10,7051.500717607177,16.0 +11,7216.2157048645295,16.0 +12,6589.7897917176415,16.0 +13,6475.80104318339,13.0 +14,6439.4163434859,13.0 +15,6543.866608779393,13.0 +16,7093.465036001735,16.0 +17,6757.44809723448,16.0 +18,6904.551072364078,16.0 +19,6675.350369769198,13.0 +20,7021.342291105484,16.0 +21,6494.906998854868,16.0 +22,6989.683508227692,16.0 +23,7060.342117872161,16.0 +24,7123.209574178231,13.0 +25,7266.365010631792,16.0 +26,7251.445393962951,16.0 +27,6656.330236205487,16.0 +28,6424.429828939011,16.0 +29,7066.849436163771,16.0 +30,7253.369565948225,16.0 +31,6978.442363573118,16.0 +32,6885.145285326886,13.0 +33,6946.9901296425505,16.0 +34,6512.521551042265,16.0 +35,6665.004996531719,16.0 +36,6789.511531020305,16.0 +37,6738.8148863974975,16.0 +38,7320.744961460436,13.0 +39,7017.344196410132,16.0 +40,7264.792748208192,16.0 +41,6955.561964184718,16.0 +42,6781.213979313943,13.0 +43,6427.086250294119,16.0 +44,6683.955901743888,16.0 +45,5366.973379780834,13.0 +46,7004.919659115017,16.0 +47,7079.4644729433685,16.0 +48,7234.318755729135,16.0 +49,6948.173876165056,13.0 +50,6719.570521151857,16.0 +51,6587.768679899307,16.0 +52,7002.334776695339,16.0 +53,6476.882502780452,16.0 +54,6794.359389228334,16.0 +55,7156.545013947016,16.0 +56,6656.635646965103,16.0 +57,6863.35786749546,16.0 +58,6742.683432799005,16.0 +59,7775.248641502792,16.0 +60,6615.35738330774,16.0 +61,6223.759804658276,13.0 +62,6562.7477218648555,16.0 +63,7641.270244264278,16.0 +64,6871.646902155131,16.0 +65,6899.876413500736,16.0 +66,7278.690345044732,16.0 +67,7275.671690408349,16.0 +68,7076.685840245986,16.0 +69,5141.4446956918755,13.0 +70,7328.401230513089,16.0 +71,6863.790012754111,16.0 +72,7026.412884135474,16.0 +73,7301.651117051579,16.0 +74,6409.227403219812,13.0 +75,6567.213961979742,13.0 +76,6663.508475995368,16.0 +77,7578.953888858407,16.0 +78,7155.890994996379,16.0 +79,6937.780072897207,16.0 +80,6710.903428646368,16.0 +81,6820.6525235469435,16.0 +82,6697.00836153118,16.0 +83,7292.794307084686,16.0 +84,7545.835694224122,16.0 +85,6921.265195182353,16.0 +86,6736.327830387691,16.0 +87,6842.6715263192555,16.0 +88,6508.873920798973,16.0 +89,6626.557140609311,16.0 +90,6666.8699271853,16.0 +91,6695.19649852262,16.0 +92,6930.479641577,16.0 +93,6623.221475487163,16.0 +94,6989.950575953237,16.0 +95,7093.563345244263,16.0 +96,6950.564904384792,16.0 +97,6908.206776726623,16.0 +98,7110.7916567199545,16.0 +99,7518.08562269474,16.0 diff --git a/train_heuristics.py b/train_heuristics.py index f879dc7..b026bd7 100644 --- a/train_heuristics.py +++ b/train_heuristics.py @@ -6,50 +6,66 @@ import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as mticker +from qsimpy import TaskStatus # Import TaskStatus +import numpy as np # Import numpy +import random # Import random for Random Best-N class HeuristicSolutions: def __init__(self, env, num_episodes=100): - - # Initialize the environment self.env = env self.num_episodes = num_episodes - - # Initialize the results of heuristic solutions self.results = [] - # Round Robin index for the QNodes. Example: [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, ...] self.rr_index = 0 - # Priority index of Greedy solution after sorting the QNodes based on the waiting time self.greedy_index = 0 + + # --- NEW: Attributes for WRR --- + self.wrr_list = [] + self.wrr_index = 0 + # --- END NEW --- + + # --- NEW: Helper method to initialize algorithms for each episode --- + def _initialize_episode_strategies(self): + """Initializes/resets strategies that require setup at the start of an episode.""" + # Create the weighted list for Weighted Round Robin (WRR) based on CLOPS + qnodes = self.env.unwrapped.qnodes + self.wrr_list = [] + # We use a base multiplier to avoid tiny floats and ensure integer repetitions + clops_values = [node.clops for node in qnodes] + min_clops = min(c for c in clops_values if c > 0) + + for i, node in enumerate(qnodes): + # The weight is how many times a node's index appears in the list + weight = int(round(node.clops / min_clops)) + self.wrr_list.extend([i] * weight) + + random.shuffle(self.wrr_list) # Shuffle to distribute nodes evenly + self.wrr_index = 0 + # --- END NEW --- + def run(self, control): """ Run the heuristic solutions for the given algorithm (control). Args: - - control (str): The heuristic algorithm to use. Options: "greedy", "random", "round_robin", "greedy_error" + - control (str): The heuristic algorithm to use. """ - self.results = [] - # Reset the subset of QTasks self.env.unwrapped.round = 1 - # **FIX:** Use an episode counter to provide a unique seed for each episode for episode_num in range(self.num_episodes): - - # Initialize the temporary array to store the results of the QTasks execution for each episode - arr_temp = { - "total_completion_time": 0.0, - "rescheduling_count": 0.0 - } + arr_temp = {"total_completion_time": 0.0, "rescheduling_count": 0.0} terminated = False - # **FIX:** Pass the unique seed here to generate a new problem for each episode self.env.reset(seed=episode_num) self.env.unwrapped.setup_quantum_resources() self.rr_index = 0 self.greedy_index = 0 + + # --- NEW: Initialize strategies for the episode --- + self._initialize_episode_strategies() + # --- END NEW --- while not terminated: - # Get the action with the given control if control == "greedy": action = self.greedy(self.greedy_index) elif control == "random": @@ -58,156 +74,263 @@ def run(self, control): action = self.round_robin() elif control == "greedy_error": action = self.greedy_error(self.greedy_index) + elif control == "ect": + action = self.earliest_completion_time() + elif control == "sjf": + action = self.shortest_job_first() + # --- NEW ALGORITHMS --- + elif control == "luf": + action = self.lowest_utilization_first() + elif control == "wrr": + action = self.weighted_round_robin() + elif control == "rbn": + action = self.random_best_n(n=3) + # --- END NEW ALGORITHMS --- - # Save the task object before it gets processed by the step function task_to_be_scheduled = self.env.unwrapped.current_qtask - obs, reward, terminated, done, info = self.env.step(action) - # If the action was invalid (e.g., node busy), increment the index for greedy strategies and try again - if reward < 0: # A reward of -0.1 indicates a penalty for an invalid action + if reward < 0: self.greedy_index += 1 - - # If the action was valid and the task was scheduled if reward > 0: - # Reset priority index of Greedy solution for the next task self.greedy_index = 0 - - # Use the saved task object to access its properties arr_temp["total_completion_time"] += task_to_be_scheduled.waiting_time + task_to_be_scheduled.execution_time arr_temp["rescheduling_count"] += task_to_be_scheduled.rescheduling_count sys.stdout.write("\033[F\033[K") print(f"[{control}] progress: {episode_num + 1}/{self.num_episodes}") self.env.unwrapped.qsp_env.run() - # Final results of the episode self.results.append(arr_temp) + + if episode_num == self.num_episodes - 1: + self._collect_and_summarize_metrics(control) - # Save the results to a CSV file self._save_to_csv(control) - + def greedy(self, greedy_index): - # Sort the QNodes based on the next available time (or waiting time) and select the QNode with the smallest waiting time greedy_strategy = sorted(self.env.unwrapped.qnodes, key=lambda x: x.next_available_time) - # Prevent index error if all nodes are invalid safe_index = min(greedy_index, len(greedy_strategy) - 1) return self.env.unwrapped.qnodes.index(greedy_strategy[safe_index]) def random(self): - # Randomly select a QNode - action = self.env.action_space.sample() - return action - + return self.env.action_space.sample() + def round_robin(self): - # Select the QNode based on the Round Robin index action = self.rr_index % self.env.unwrapped.n_qnodes self.rr_index += 1 return action - + def greedy_error(self, greedy_index, g_error="Readout_assignment_error"): - # Sort the QNodes based on the next available time and then by error greedy_strategy = sorted(self.env.unwrapped.qnodes, key=lambda x: (x.next_available_time, x.error[g_error])) - # Prevent index error if all nodes are invalid safe_index = min(greedy_index, len(greedy_strategy) - 1) return self.env.unwrapped.qnodes.index(greedy_strategy[safe_index]) - def _save_to_csv(self, control) -> None: + def earliest_completion_time(self): + qtask = self.env.unwrapped.current_qtask + qnodes = self.env.unwrapped.qnodes + broker = self.env.unwrapped.broker + completion_times = [] + for node in qnodes: + processed_task, waiting_time, execution_time = broker.preprocess_qtask(qtask, node) + if processed_task.status == TaskStatus.ERROR: + completion_times.append(float('inf')) + else: + est_completion_time = self.env.unwrapped.qsp_env.now + waiting_time + execution_time + completion_times.append(est_completion_time) + if all(ct == float('inf') for ct in completion_times): + return self.random() + return np.argmin(completion_times) + + def shortest_job_first(self): + qtask = self.env.unwrapped.current_qtask + qnodes = self.env.unwrapped.qnodes + broker = self.env.unwrapped.broker + execution_times = [] + for node in qnodes: + processed_task, _, execution_time = broker.preprocess_qtask(qtask, node) + if processed_task.status == TaskStatus.ERROR: + execution_times.append(float('inf')) + else: + execution_times.append(execution_time) + if all(et == float('inf') for et in execution_times): + return self.random() + return np.argmin(execution_times) + + def lowest_utilization_first(self): """ - Save values and episodes to a CSV file. + Assigns the task to the node that has been historically the least busy. + Utilization = Total Busy Time of a Node / Total Simulation Time """ + qnodes = self.env.unwrapped.qnodes + # We use getattr to safely get total_busy_time, defaulting to 0 if not present + busy_times = [getattr(node, 'total_busy_time', 0.0) for node in qnodes] + + # Check for invalid tasks on each node + valid_nodes = [] + for i, node in enumerate(qnodes): + # A simple validity check without full preprocessing + if self.env.unwrapped.current_qtask.qubit_number <= node.qubit_number: + valid_nodes.append(i) + + if not valid_nodes: + return self.random() # All nodes are invalid for this task - file_name = "./results/heuristics/" + # Find the node with the minimum busy time *among the valid ones* + min_busy_time = float('inf') + action = -1 + for i in valid_nodes: + if busy_times[i] < min_busy_time: + min_busy_time = busy_times[i] + action = i + + return action - if not os.path.exists(file_name): - os.makedirs(file_name) + def weighted_round_robin(self): + """ + Assigns tasks in a round-robin fashion but gives more time slots + to more powerful nodes (based on CLOPS). + """ + if not self.wrr_list: # Failsafe if list is empty + return self.random() + + action = self.wrr_list[self.wrr_index % len(self.wrr_list)] + self.wrr_index += 1 + return action + def random_best_n(self, n=3): + """ + A hybrid approximation algorithm. Randomly selects N nodes and then + applies the optimal ECT strategy to that subset. + """ + qnodes = self.env.unwrapped.qnodes + num_qnodes = len(qnodes) + + # Create a list of node indices [0, 1, 2, 3, 4] + node_indices = list(range(num_qnodes)) + + # If N is larger than available nodes, just use all nodes + n = min(n, num_qnodes) + + # Randomly sample N unique indices + sampled_indices = random.sample(node_indices, n) + + # Now, apply the ECT logic only on the sampled nodes + qtask = self.env.unwrapped.current_qtask + broker = self.env.unwrapped.broker + + best_completion_time = float('inf') + action = -1 + + for index in sampled_indices: + node = qnodes[index] + processed_task, waiting_time, execution_time = broker.preprocess_qtask(qtask, node) + + if processed_task.status != TaskStatus.ERROR: + est_completion_time = self.env.unwrapped.qsp_env.now + waiting_time + execution_time + if est_completion_time < best_completion_time: + best_completion_time = est_completion_time + action = index + + # If no valid node was found in the sample, fall back to random + return action if action != -1 else self.random() + + def _save_to_csv(self, control) -> None: + file_name = "./results/heuristics/" + if not os.path.exists(file_name): os.makedirs(file_name) file_name += control + ".csv" - # Open the CSV file in write mode with open(file_name, mode='w', newline='') as file: writer = csv.writer(file) - - # Write the header writer.writerow(['Episode', 'Total Completion Time', 'Rescheduling Count']) - - # Write the data for i in range(len(self.results)): writer.writerow([i, self.results[i]['total_completion_time'], self.results[i]['rescheduling_count']]) print("CSV file saved to " + file_name) def _plot_results(self, paths) -> None: - """ - Plot the results of the episodes. - """ - plt.figure(figsize=(12, 7)) + plt.figure(figsize=(14, 8)) for path in paths: df1 = pd.read_csv(path['path']) - plt.plot(df1['Episode'], df1['Total Completion Time'], ".-", color=path['color'], label=path['label']) - self._summarize_results(df1, path['label']) - plt.ylabel('Total Completion Time') plt.xlabel('Evaluation Episode') plt.title('Heuristic Method Performance Comparison') plt.legend(loc='best') plt.grid(True) plt.gca().xaxis.set_major_locator(mticker.MultipleLocator(10)) + if not os.path.exists("./results/heuristics/"): os.makedirs("./results/heuristics/") + plt.savefig("./results/heuristics/performance_comparison.png") plt.show() def _summarize_results(self, values, label) -> None: - """ - Summarize the results of the episodes. - """ - print("\n--- Results Summary for " + label + " solution ---") + print(f"\n--- Results Summary for {label} solution ---") print(f"Number of Episodes: {self.num_episodes}") print(f"Average Total Completion Time: {sum(values['Total Completion Time']) / self.num_episodes:.2f}") print(f"Average Rescheduling Count: {sum(values['Rescheduling Count']) / self.num_episodes:.2f}") print("------------------------------------------") + + def _collect_and_summarize_metrics(self, control): + serviced_tasks = self.env.unwrapped.serviced_qtasks + qnodes = self.env.unwrapped.qnodes + total_sim_time = self.env.unwrapped.qsp_env.now + if not serviced_tasks: + print(f"\n--- No tasks were serviced for {control}. Cannot generate metrics. ---") + return + total_qtasks = len(serviced_tasks) + avg_wait_time = sum(task.waiting_time for task in serviced_tasks) / total_qtasks + throughput = total_qtasks / total_sim_time if total_sim_time > 0 else 0 + failure_threshold = 5 + failed_tasks = sum(1 for task in serviced_tasks if task.rescheduling_count >= failure_threshold) + success_rate = (total_qtasks - failed_tasks) / total_qtasks * 100 + print(f"\n--- Detailed Metrics Summary for '{control}' ---") + print(f"Total Simulation Time: {total_sim_time:.2f}s") + print(f"Throughput: {throughput:.4f} tasks/sec") + print(f"Average Wait Time per Task: {avg_wait_time:.4f}s") + print(f"Success Rate (rescheduled < {failure_threshold} times): {success_rate:.2f}%") + print(f"Number of Failed Tasks: {failed_tasks}") + print("\n--- Quantum Computer Utilization ---") + for node in qnodes: + busy_time = getattr(node, 'total_busy_time', 0.0) + utilization = (busy_time / total_sim_time) * 100 if total_sim_time > 0 else 0 + print(f" - {node.name} (ID: {node.id}): {utilization:.2f}% utilization") + print("------------------------------------------") if __name__ == "__main__": - - # Create the QSimPy environment - env_config={ - "obs_filter": "rescale_-1_1", - "reward_filter": None, - "dataset": "qdataset/qsimpyds_1000_sub_26.csv", - } - + env_config = { + "obs_filter": "rescale_-1_1", + "reward_filter": None, + "dataset": "qdataset/qsimpyds_1000_sub_26.csv", + } env = qsimpy_env_creator(env_config) - - # Run the heuristic solutions + + print("\n\n\n") + heuristics = HeuristicSolutions(env, num_episodes=100) - methods = ['greedy','random','round_robin','greedy_error'] - processes = [Process(target=heuristics.run , args=(m,)) for m in methods] - for p in processes: - p.start() - for p in processes: - p.join() + heuristics.run("sjf") + # methods = [ + # 'greedy', 'random', 'round_robin', 'greedy_error', + # 'ect', 'sjf', 'luf', 'wrr', 'rbn' + # ] + + + # processes = [Process(target=heuristics.run, args=(m,)) for m in methods] + # for p in processes: + # p.start() + # for p in processes: + # p.join() print("All Processes are done!!") - # Plot the results + # --- UPDATE PATHS FOR PLOTTING --- paths = [ - { - "label": "Random", - "path": "./results/heuristics/random.csv", - "color": "red" - }, - { - "label": "Round Robin", - "path": "./results/heuristics/round_robin.csv", - "color": "blue" - }, - { - "label": "Greedy", - "path": "./results/heuristics/greedy.csv", - "color": "black" - }, - { - "label": "Greedy + Error", - "path": "./results/heuristics/greedy_error.csv", - "color": "green" - }, - + {"label": "Random", "path": "./results/heuristics/random.csv", "color": "red"}, + {"label": "Round Robin", "path": "./results/heuristics/round_robin.csv", "color": "blue"}, + {"label": "Greedy (Earliest Available)", "path": "./results/heuristics/greedy.csv", "color": "black"}, + {"label": "Greedy + Error", "path": "./results/heuristics/greedy_error.csv", "color": "green"}, + {"label": "Earliest Completion Time (ECT)", "path": "./results/heuristics/ect.csv", "color": "purple"}, + {"label": "Shortest Job First (SJF)", "path": "./results/heuristics/sjf.csv", "color": "orange"}, + {"label": "Lowest Utilization First (LUF)", "path": "./results/heuristics/luf.csv", "color": "cyan"}, + {"label": "Weighted Round Robin (WRR)", "path": "./results/heuristics/wrr.csv", "color": "magenta"}, + {"label": "Random Best-3 (RBN)", "path": "./results/heuristics/rbn.csv", "color": "brown"}, ] + # --- END UPDATE --- heuristics._plot_results(paths) \ No newline at end of file diff --git a/zolution/TASK.jpg b/zolution/TASK.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5fdfd64a3721c39fa24506e8a3b17b21e1fe22f0 GIT binary patch literal 28029 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�<#?^#zdBSEq!t+bEm&d!cQm)K%jb+xV`2kjNp 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 t!~l@N-B)iS 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 F{129NUQ+-7 literal 0 HcmV?d00001 From dad8d8634644cb89bc31172a63ba0a6ae4650996 Mon Sep 17 00:00:00 2001 From: mopoa Date: Mon, 29 Sep 2025 09:15:48 +0330 Subject: [PATCH 8/8] some fixes --- evaluator_greedy.py | 2 +- train_heuristics.py | 10 ++++------ zolution/shahrivar.present.odt | Bin 0 -> 36128 bytes 3 files changed, 5 insertions(+), 7 deletions(-) create mode 100644 zolution/shahrivar.present.odt diff --git a/evaluator_greedy.py b/evaluator_greedy.py index 2c64ede..f5397dc 100644 --- a/evaluator_greedy.py +++ b/evaluator_greedy.py @@ -16,7 +16,7 @@ def enhanced_greedy_policy(env, skipped_list): - current_obs = env.current_obs + current_obs = env.unwrapped.current_obs qnode_start_index = 4 # Adjust based on the actual qtask observation length qnode_obs_length = 3 # Number of values per qnode in the observation diff --git a/train_heuristics.py b/train_heuristics.py index b026bd7..2d0e54b 100644 --- a/train_heuristics.py +++ b/train_heuristics.py @@ -6,9 +6,9 @@ import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as mticker -from qsimpy import TaskStatus # Import TaskStatus -import numpy as np # Import numpy -import random # Import random for Random Best-N +from qsimpy import TaskStatus +import numpy as np +import random class HeuristicSolutions: def __init__(self, env, num_episodes=100): @@ -23,7 +23,6 @@ def __init__(self, env, num_episodes=100): self.wrr_index = 0 # --- END NEW --- - # --- NEW: Helper method to initialize algorithms for each episode --- def _initialize_episode_strategies(self): """Initializes/resets strategies that require setup at the start of an episode.""" # Create the weighted list for Weighted Round Robin (WRR) based on CLOPS @@ -40,8 +39,6 @@ def _initialize_episode_strategies(self): random.shuffle(self.wrr_list) # Shuffle to distribute nodes evenly self.wrr_index = 0 - # --- END NEW --- - def run(self, control): """ @@ -270,6 +267,7 @@ def _summarize_results(self, values, label) -> None: def _collect_and_summarize_metrics(self, control): serviced_tasks = self.env.unwrapped.serviced_qtasks + serviced_tasks = self.env qnodes = self.env.unwrapped.qnodes total_sim_time = self.env.unwrapped.qsp_env.now if not serviced_tasks: diff --git a/zolution/shahrivar.present.odt b/zolution/shahrivar.present.odt new file mode 100644 index 0000000000000000000000000000000000000000..c389a5204899d528ecfd3812df9d466685ca2806 GIT binary patch literal 36128 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 m%oJE0AQw!a>Hq