diff --git a/LUKE best front.csv b/LUKE best front.csv new file mode 100644 index 0000000..a9b1638 --- /dev/null +++ b/LUKE best front.csv @@ -0,0 +1,142 @@ +npv4% ,SV30 ,removal1 ,removal2 ,removal3 ,dummy +max,max,max,max,max,var +-1.43181E+11,-1385313588,-1822843650,-826674151.5,-1062581206,1 +-1.06682E+11,-5130174379,-115407634.5,-15457198.81,-3798958.49,1 +-1.37406E+11,-662648930.9,-1948668143,-634974365.4,-1378500686,1 +-1.24318E+11,-170340782.9,-18055990.55,-3487006420,-638888192.6,1 +-1.11526E+11,1233012925.9199994 ,-22797924.96,-19563760.88,-5708832886,1 +-1.37102E+11,-2231378767,-1069170660,-1905523458,-2194423.7,1 +-1.37456E+11,-2970267173,-1293362325,-1151468334,-2194145.6,1 +-1.31604E+11,-2685242296,-1206870366,-2317605.25,-1613952639,1 +-1.27839E+11,-1778291767,-931817868.3,-2194071.85,-2702795317,1 +-1.31356E+11,-2630641685,-546778903,-2118196017,-2194145.6,1 +-1.28139E+11,-2507862734,-536323798.6,-889286243.3,-1454871319,1 +-1.24635E+11,-1896718753,-631559346.2,-3512260.25,-2809188573,1 +-1.26038E+11,-2141348733,-125684167.7,-1850264867,-1126321040,1 +-1.23788E+11,-1749112002,-405870252.7,-473842756.1,-2676805007,1 +-1.22331E+11,-1355445335,-56535506.12,-1419867779,-2323579116,1 +-1.35899E+11,-629666161.5,-1189176792,-2116103671,-596876983.2,1 +-1.39288E+11,-874201631,-1301000200,-1156252650,-1891987630,1 +-1.3252E+11,-553578737.8,-1203826174,-1451055.41,-3506658737,1 +-1.33623E+11,-638295560.6,-585959410.1,-2188393364,-1680421756,1 +-1.28208E+11,-398566811.3,-513169117.3,-895208736,-3367640972,1 +-1.25997E+11,-12940185.3,-79695107.22,-1845876882,-3021803432,1 +-1.35307E+11,460866955.5400055 ,-1186220907,-2110462913,-1552910241,1 +-1.3542E+11,709175982.0499891 ,-1175282935,-928873862.8,-3422801331,1 +-1.29351E+11,745744571.7,-433600501,-1913469841,-3132598160,1 +-1.34889E+11,631159521.3999939 ,-949743961.9,-1683532575,-2756146293,1 +-1.37113E+11,-2235697021,-1070482966,-1901526494,-2194423.7,1 +-1.3443E+11,-2311284037,-1093555525,-781190847,-1278581527,1 +-1.27839E+11,-1778291767,-931817868.3,-2194071.85,-2702795317,1 +-1.28938E+11,-2070992513,-377111095.3,-1811456067,-1063050087,1 +-1.20088E+11,-1794965304,-293357921.3,-498243122,-2717758923,1 +-1.22329E+11,-1355625513,-56553613.48,-1419485143,-2323750735,1 +-1.3803E+11,-318598340.1,-1132374832,-2013220988,-1393704463,1 +-1.34521E+11,-158103528.7,-1083790386,-763523214.6,-3151988785,1 +-1.28986E+11,81931474.86000235 ,-367379136.7,-1793870469,-2936720483,1 +-1.34889E+11,631159521.3999939 ,-949743961.9,-1683532575,-2756146293,1 +-1.36606E+11,-1834065204,-948870434.9,-1681689200,-850615252.7,1 +-1.29301E+11,-1597718597,-877034996.6,-390280449.6,-2540854431,1 +-1.23945E+11,-1340511929,-155502617.8,-1411347991,-2310193108,1 +-1.35559E+11,345305629.4900028 ,-930946797.6,-1649577995,-2700519840,1 +-1.32306E+11,-1136989046,-737372755.8,-1299713849,-2127676371,1 +-1.32321E+11,-1133027275,-736020327.8,-1306318819,-2125116081,1 +-1.22329E+11,-1355625513,-56553613.48,-1419485143,-2323750735,1 +-1.34891E+11,631071258.0299939 ,-949743245.3,-1683532622,-2756151855,1 +-1.27839E+11,-1778291767,-931817868.3,-2194071.85,-2702795317,1 +-1.3752E+11,-2160390590,-1047708917,-1860369288,-192350513.7,1 +-1.22329E+11,-1355625513,-56553613.48,-1419485143,-2323750735,1 +-1.27839E+11,-1778291767,-931817868.3,-2194071.85,-2702795317,1 +-1.37113E+11,-2235697021,-1070482966,-1901526494,-2194423.7,1 +-1.24634E+11,-1896771597,-631555553.2,-3512260.25,-2809118742,1 +-1.30835E+11,713724889.5,-563708644.4,-1857880807,-3041587069,1 +-1.38107E+11,-754810895.5,-1103917443,-1526075614,-1784915392,1 +-1.32013E+11,-321046002.6,-731015806.1,-1288457970,-2822565154,1 +-1.26574E+11,-2234990969,-144725011.7,-1901266639,-972455394,1 +-1.26493E+11,165374506.23000374 ,-92552084.07,-1893356760,-3099666878,1 +-1.17849E+11,-1720165379,-65743717.96,-747825271.7,-2650689589,1 +-1.29876E+11,-1840881602,-468132406.6,-1685332025,-1332272407,1 +-1.36684E+11,-984234555.6,-1173346514,-2087152315,-563642732.9,1 +-1.34006E+11,-2020289889,-1005330155,-912244465,-1493188969,1 +-1.20327E+11,-1964280363,-505644671.9,-10049691.56,-2869723397,1 +-1.23493E+11,-1640946306,-407510774.8,-704412793.4,-2579645979,1 +-1.35518E+11,268466241.48000085 ,-1189268564,-2115975040,-1324168616,1 +-1.35392E+11,689497714.6199923 ,-1119631236,-1118826334,-3258248163,1 +-1.30471E+11,-2673810032,-479457759.4,-2141491635,-2194145.6,1 +-1.37011E+11,-2539841136,-1162821340,-1196846141,-532472648.7,1 +-1.32083E+11,-2789773263,-1238699711,-26588221.82,-1469951470,1 +-1.32986E+11,-388809631.9,-1234162627,-18477067.39,-3596666576,1 +-1.34726E+11,-33000695.62,-1126210938,-694982680.3,-3277570965,1 +-1.28511E+11,237711454.1400056 ,-320058949,-1853726427,-3034786872,1 +-1.36386E+11,-93757869.74,-903448067.4,-2035488041,-1905399079,1 +-1.28442E+11,-2185177582,-331282451,-1873827227,-927757836.6,1 +-1.28181E+11,-128503935.1,-431403124.1,-1183031284,-3363220046,1 +-1.27307E+11,-2362804560,-556451508.6,-664076136.6,-1800351162,1 +-1.32108E+11,-1567795324,-1109156693,-228571084.6,-2514015485,1 +-1.24284E+11,-1165978047,-52510972.11,-1751349342,-2153660948,1 +-1.31793E+11,-501353189.2,-544287336.6,-1822894829,-2270939834,1 +-1.26684E+11,-1458522902,-354136015.5,-1040153325,-2416017153,1 +-1.35707E+11,-779569609,-1189278108,-2115987352,-456904931.9,1 +-1.34493E+11,371031878.9100036 ,-762373992.3,-2216402326,-2201900115,1 +-1.26571E+11,-2234322912,-751713717.3,-3758088.21,-2398464278,1 +-1.35281E+11,-2394430162,-877359324.8,-1988640991,-2194423.7,1 +-1.37209E+11,-1118656564,-973098656,-1725315705,-1397890119,1 +-1.3922E+11,189308329.7000036 ,-1300169751,-1444670025,-2364866557,1 +-1.28269E+11,-939401375.2,-194622093.3,-2062916337,-1950475157,1 +-1.31366E+11,-1313245775,-790745450.1,-960516788.7,-2285741906,1 +-1.2814E+11,-917227643,-673221116.9,-307898828.9,-3357233589,1 +-1.37321E+11,-2972377493,-1294046205,-998019601,-207143183.7,1 +-1.35748E+11,567337989.7199997 ,-1051832258,-1867803808,-2344505828,1 +-1.37028E+11,276950234.7100056 ,-1032188213,-1832331246,-2286270563,1 +-1.35699E+11,-1663909934,-897088159.5,-1588344557,-1173562633,1 +-1.35668E+11,-1274311666,-778995924.4,-2246273660,-824161150.1,1 +-1.33525E+11,-3620204332,-1312693850,-4840089.56,-588902908.4,1 +-1.35214E+11,695094616.4599943 ,-1321651649,-24548399.2,-4229306178,1 +-1.34999E+11,394449589.12999886 ,-614067317.5,-2502681332,-1945687457,1 +-1.385E+11,-978665892.8,-1829151750,-1238471007,-628370640.4,1 +-1.36608E+11,-661792539.4,-1313110997,-1957747358,-616883985.7,1 +-1.35486E+11,-1372985493,-622646614.1,-2627384571,-258685182.6,1 +-1.36813E+11,-2886220877,-1003032249,-1324671958,-184368740,1 +-1.33918E+11,-1619758079,-1167268252,-4158828.46,-2578977006,1 +-1.41883E+11,-1475509301,-1946943751,-748521809.5,-816420060.8,1 +-1.35862E+11,689087150.7299924 ,-1099742339,-681870801.9,-3751682423,1 +-1.32584E+11,-383924335.5,-598740930.2,-2817749667,-696409174.5,1 +-1.35572E+11,-3878211298,-1492929276,-113423849.5,-33654349.26,1 +-1.3847E+11,-150688591.1,-1094818950,-1121769882,-2688005104,1 +-1.3696E+11,341284634.24000216 ,-1431729736,-7812135.07,-3899764282,1 +-1.25754E+11,-4373943455,-827551201.3,-291640631.4,-17653239.18,1 +-1.36691E+11,-2449661058,-1424751925,-5351324.24,-1566350661,1 +-1.39591E+11,497154514.84999925 ,-1866986169,-971705711.8,-2245241299,1 +-1.24384E+11,-3164156600,-704826786.5,-3779299.02,-1571050076,1 +-1.35933E+11,-562674480.5,-605286790.7,-2440113402,-1323154544,1 +-1.38016E+11,-1710773758,-1068711375,-1074617632,-1474074429,1 +-1.26711E+11,903790414.0799905 ,-743549204.2,-14970701.84,-4956553047,1 +-1.37064E+11,484468156.0799987 ,-890974714.8,-1779849095,-2608760446,1 +-1.37784E+11,-797694577.6,-1577667633,-1607380887,-617838964.9,1 +-1.39422E+11,-932283062.9,-1462903553,-301056670.3,-2560758890,1 +-1.29579E+11,823060728.3899903 ,-523982813.9,-1118882526,-3952960416,1 +-1.35033E+11,-679701855.1,-551557773,-2735590461,-788991459,1 +-1.34356E+11,718541782.1199945 ,-1254951985,-15486160.22,-4323478955,1 +-1.3767E+11,-2718891952,-1289073064,-558750352.2,-884171992.3,1 +-1.39746E+11,-2383046605,-1948667573,-179424793.7,-654420933.6,1 +-1.35416E+11,-364484146.3,-591276355.1,-2681955506,-1075604496,1 +-1.37107E+11,-2453337812,-892506531.5,-1884236425,-29281217.81,1 +-1.38295E+11,-599519709.7,-1173448174,-2085254714,-814968668.4,1 +-1.306E+11,-274636919.9,-935112749.7,-2880850.69,-3947191477,1 +-1.30656E+11,420228730.0199975 ,-229528507,-3040404198,-1712101713,1 +-1.39988E+11,-1513257296,-1291752270,-1479946090,-959153304.2,1 +-1.40359E+11,-476457442.3,-1195488902,-1403473561,-1984772862,1 +-1.35129E+11,228005254.7100049 ,-637901589.3,-1931289622,-2560651561,1 +-1.33493E+11,-3578670775,-1001224976,-865283938.3,-19785183.05,1 +-1.37366E+11,-729097018,-1472031006,-1749698206,-626122572.4,1 +-1.34142E+11,-493270501.2,-937203939.3,-2430006940,-626317895.6,1 +-1.33924E+11,630238208.8,-658948585.8,-1678068687,-3083496453,1 +-1.36708E+11,-1623452924,-740108693.7,-1967838377,-880440309.3,1 +-1.41482E+11,-866276878.2,-1882835146,-178803909.9,-2169979654,1 +-1.40981E+11,-1295462600,-1859236507,-223677168.5,-1850683695,1 +-1.39334E+11,-1102319154,-1947086880,-918484406.6,-773451812.4,1 +-1.29341E+11,-3136660743,-570643539.1,-1167737489,-546990356.5,1 +-1.33233E+11,-2627606708,-1020998020,-397897251.6,-1404498712,1 +-1.3653E+11,232096528.62000242 ,-1080899341,-712912625.7,-3447307994,1 +-1.39762E+11,292789616.7700043 ,-1901779813,-188184193.1,-3059534898,1 +-1.37086E+11,-622306712.9,-1340339351,-1921185524,-684250996.9,1 \ No newline at end of file diff --git a/app.py b/app.py index 5096f92..4ef529b 100644 --- a/app.py +++ b/app.py @@ -39,6 +39,7 @@ user_resources, solution_archive_resources, log_resources, + nimbus, ) # noqa: E402 # import views @@ -72,6 +73,10 @@ def check_if_token_revoked(jwt_header, jwt_payload): api.add_resource(method_resources.MethodCreate, "/method/create") api.add_resource(method_resources.MethodControl, "/method/control") +# Add nimbus endpoints + +api.add_resource(nimbus.Iterate, "/nimbus/iterate") + # Add questionnaire endpoints api.add_resource( questionnaire_resources.QuestionnaireAfterSolutionProcess, "/questionnaire/after" @@ -80,9 +85,13 @@ def check_if_token_revoked(jwt_header, jwt_payload): questionnaire_resources.QuestionnaireDuringSolutionProcess, "/questionnaire/during" ) api.add_resource( - questionnaire_resources.QuestionnaireDuringSolutionProcessFirstIteration, "/questionnaire/during/first" + questionnaire_resources.QuestionnaireDuringSolutionProcessFirstIteration, + "/questionnaire/during/first", +) +api.add_resource( + questionnaire_resources.QuestionnaireDuringSolutionProcessAfterNew, + "/questionnaire/during/new", ) -api.add_resource(questionnaire_resources.QuestionnaireDuringSolutionProcessAfterNew, "/questionnaire/during/new") # Add archive endpoint api.add_resource(solution_archive_resources.Archive, "/archive") diff --git a/poetry.lock b/poetry.lock index b6cc7e8..e1b7fd0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -1915,28 +1915,28 @@ docutils = ">=0.7" [[package]] name = "ruff" -version = "0.1.6" +version = "0.1.14" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703"}, - {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462"}, - {file = "ruff-0.1.6-py3-none-win32.whl", hash = "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a"}, - {file = "ruff-0.1.6-py3-none-win_amd64.whl", hash = "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33"}, - {file = "ruff-0.1.6-py3-none-win_arm64.whl", hash = "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc"}, - {file = "ruff-0.1.6.tar.gz", hash = "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184"}, + {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:96f76536df9b26622755c12ed8680f159817be2f725c17ed9305b472a757cdbb"}, + {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab3f71f64498c7241123bb5a768544cf42821d2a537f894b22457a543d3ca7a9"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7060156ecc572b8f984fd20fd8b0fcb692dd5d837b7606e968334ab7ff0090ab"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a53d8e35313d7b67eb3db15a66c08434809107659226a90dcd7acb2afa55faea"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea9be712b8f5b4ebed40e1949379cfb2a7d907f42921cf9ab3aae07e6fba9eb"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2270504d629a0b064247983cbc495bed277f372fb9eaba41e5cf51f7ba705a6a"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80258bb3b8909b1700610dfabef7876423eed1bc930fe177c71c414921898efa"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:653230dd00aaf449eb5ff25d10a6e03bc3006813e2cb99799e568f55482e5cae"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b3acc6c4e6928459ba9eb7459dd4f0c4bf266a053c863d72a44c33246bfdbf"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b3dadc9522d0eccc060699a9816e8127b27addbb4697fc0c08611e4e6aeb8b5"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1c8eca1a47b4150dc0fbec7fe68fc91c695aed798532a18dbb1424e61e9b721f"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:62ce2ae46303ee896fc6811f63d6dabf8d9c389da0f3e3f2bce8bc7f15ef5488"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b2027dde79d217b211d725fc833e8965dc90a16d0d3213f1298f97465956661b"}, + {file = "ruff-0.1.14-py3-none-win32.whl", hash = "sha256:722bafc299145575a63bbd6b5069cb643eaa62546a5b6398f82b3e4403329cab"}, + {file = "ruff-0.1.14-py3-none-win_amd64.whl", hash = "sha256:e3d241aa61f92b0805a7082bd89a9990826448e4d0398f0e2bc8f05c75c63d99"}, + {file = "ruff-0.1.14-py3-none-win_arm64.whl", hash = "sha256:269302b31ade4cde6cf6f9dd58ea593773a37ed3f7b97e793c8594b262466b67"}, + {file = "ruff-0.1.14.tar.gz", hash = "sha256:ad3f8088b2dfd884820289a06ab718cde7d38b94972212cc4ba90d5fbc9955f3"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 5980ce8..5ce476e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,96 @@ sphinx-rtd-theme = "^0.5.1" pytest = "^6.2.3" matplotlib = "^3.4.2" +[tool.ruff] +# Enable the pycodestyle (`E`) and Pyflakes (`F`) rules by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +select = [ + "E", + "F", + "W", + "C901", + "D", + "UP", + "S", + "FBT", + "B", + "A", + "COM", + "C4", + "T20", + "PIE", + "RET", + "PTH", + "TD", # Comment this out if too annoying + "FIX", # Comment this out if too annoying + "SIM", + "PL", + "TRY", + "FURB", + "LOG", + "NPY", + "RUF", + "I", + "N", +] +ignore = [ + "COM812", # Enforcing trailing commas is too annoying. + "PLR0915", # "too many statements (>50)" + "T201", # allow print statements +] +pydocstyle.convention = "google" + + +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = [] +unfixable = [] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] + +line-length = 120 + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# Assume Python 3.11. +target-version = "py312" + +[tool.ruff.per-file-ignores] +# Ignore certain rules in test files +"tests/**/*.py" = [ + "S101", # asserts allowed in tests... + "ARG", # Unused function args -> fixtures nevertheless are functionally relevant... + "FBT", # Don't care about booleans as positional arguments in tests, e.g. via @pytest.mark.parametrize() + "PLR2004", # Magic value used in comparison, ... +] + +[tool.ruff.format] +quote-style = "double" + [tool.poetry.group.dev.dependencies] pytest-rerunfailures = "^11.1.2" diff --git a/resources/nimbus.py b/resources/nimbus.py new file mode 100644 index 0000000..12cf2f4 --- /dev/null +++ b/resources/nimbus.py @@ -0,0 +1,291 @@ +from copy import deepcopy +from dataclasses import asdict, dataclass + +import numpy as np +import pandas as pd +import simplejson as json +from desdeo_mcdm.interactive.NIMBUS import ( + NIMBUS, + NimbusClassificationRequest, + NimbusIntermediateSolutionsRequest, + NimbusMostPreferredRequest, +) +from desdeo_problem.problem.Problem import DiscreteDataProblem, MOProblem +from flask_jwt_extended import get_jwt, get_jwt_identity, jwt_required +from flask_restx import Resource, reqparse + +from database import db +from models.problem_models import GuestProblem, Problem +from models.user_models import ( + GUEST_ROLE, + USER_ROLE, + GuestUserModel, + UserModel, + role_required, +) +from utilities.expression_parser import NumpyEncoder, numpify_dict_items + +initialize_parser = reqparse.RequestParser() +initialize_parser.add_argument( + "problemId", + type=int, + help="The id of the problem to be solved", + required=True, +) +initialize_parser.add_argument( + "initialSolution", + type=list, + help="The initial solution or preference to be evaluated.", + required=False, +) + +iterate_parser = reqparse.RequestParser() +iterate_parser.add_argument( + "problemId", + type=int, + help="The id of the problem to be solved", + required=True, +) +iterate_parser.add_argument( + "preference", + type=list, + help=( + "The preference as a reference point. Note, NIMBUS uses classification preference," + " we can construct it using this reference point and the reference solution." + ), + required=True, +) +iterate_parser.add_argument( + "referenceSolution", + type=list, + help="The reference solution to be used in the classification preference.", + required=True, +) + +intermediate_parser = reqparse.RequestParser() +intermediate_parser.add_argument( + "problemId", + type=int, + help="The id of the problem to be solved", + required=True, +) +intermediate_parser.add_argument( + "solution1", + type=list, + help="The first solution for intermediate generation.", + required=True, +) +intermediate_parser.add_argument( + "solution2", + type=list, + help="The second solution for intermediate generation.", + required=True, +) +intermediate_parser.add_argument( + "numIntermediates", + type=int, + help="The number of intermediate solutions to be generated.", + required=True, +) + +save_parser = reqparse.RequestParser() +save_parser.add_argument( + "problemId", + type=int, + help="The id of the problem these solutions are for.", + required=True, +) +save_parser.add_argument( + "solutions", + type=list, + help="The solutions to be saved. Maybe these are the database indices???", + required=True, +) + + +class NIMBUSResponse(dataclass): + """The response from most NIMBUS endpoints.""" + + objective_names: list[str] + is_maximized: list[bool] + lower_bounds: list[float] + upper_bounds: list[float] + previousp_preference: list[float] + current_solutions: list[list[float]] + saved_solutions: list[list[float]] + all_solutions: list[list[float]] + + +class Initialize(Resource): + @jwt_required() + @role_required(USER_ROLE, GUEST_ROLE) + def post(self): + # Parsing the request + data = initialize_parser.parse_args() + problem_id = data["problemId"] + initial_solution = data["initialSolution"] + # Make sure that the initial solution is a list or None + if initial_solution is not None or not isinstance(initial_solution, list): + return {"message": "Initial solution must be a list or None"}, 400 + # Getting the problem from the database, annoying to extract to a function because + # of database session issues + try: + claims = get_jwt() + current_user = get_jwt_identity() + + if claims["role"] == USER_ROLE: + current_user_id = ( + UserModel.query.filter_by(username=current_user).first().id + ) + problem_query = Problem.query.filter_by( + id=problem_id, user_id=current_user_id + ).first() + elif claims["role"] == GUEST_ROLE: + current_user_id = ( + GuestUserModel.query.filter_by(username=current_user).first().id + ) + problem_query = GuestProblem.query.filter_by( + id=problem_id, guest_id=current_user_id + ).first() + except Exception as e: + print(f"DEBUG: {e}") + # not found + return {"message": f"Could not find problem with id={problem_id}."}, 404 + + if problem_query is None: + # not found + return { + "message": "No problem with given ID found for the current user." + }, 404 + + problem: DiscreteDataProblem | MOProblem = problem_query.problem_pickle + method = NIMBUS(problem, starting_point=np.array(initial_solution)) + request = method.start() + + ideal = problem.ideal + nadir = problem.nadir + ideal_nadir = np.vstack((ideal, nadir)) + ideal_nadir = ideal_nadir * problem._max_multiplier + lower_bounds = np.min(ideal_nadir, axis=0) + upper_bounds = np.max(ideal_nadir, axis=0) + + # TODO: Get the actual current solutions, saved solutions, and all solutions + # TODO: Also, save the current solutions to the database + + response = NIMBUSResponse( + objective_names=problem.objective_names, + is_maximized=[ + bool(multiplier == -1) for multiplier in problem._max_multiplier + ], + lower_bounds=lower_bounds.tolist(), + upper_bounds=upper_bounds.tolist(), + previousPreference=initial_solution + or ((lower_bounds + upper_bounds) / 2).tolist(), + current_solutions=request.current_solutions, + saved_solutions=request.saved_solutions, + all_solutions=request.all_solutions, + ) + print(response) + + return asdict(response), 200 + + +class Iterate(Resource): + @jwt_required() + @role_required(USER_ROLE, GUEST_ROLE) + def post(self): + data = iterate_parser.parse_args() + problem_id = data["problemId"] + preference = data["preference"] + reference_solution = data["referenceSolution"] + + # Getting the problem from the database, annoying to extract to a function because + # of database session issues + try: + claims = get_jwt() + current_user = get_jwt_identity() + + if claims["role"] == USER_ROLE: + current_user_id = ( + UserModel.query.filter_by(username=current_user).first().id + ) + problem_query = Problem.query.filter_by( + id=problem_id, user_id=current_user_id + ).first() + elif claims["role"] == GUEST_ROLE: + current_user_id = ( + GuestUserModel.query.filter_by(username=current_user).first().id + ) + problem_query = GuestProblem.query.filter_by( + id=problem_id, guest_id=current_user_id + ).first() + except Exception as e: + print(f"DEBUG: {e}") + # not found + return {"message": f"Could not find problem with id={problem_id}."}, 404 + + if problem_query is None: + # not found + return { + "message": "No problem with given ID found for the current user." + }, 404 + + problem: DiscreteDataProblem | MOProblem = problem_query.problem_pickle + + + last_request = method_query.last_request + + # cast lists, which have numerical content, to numpy arrays + user_response = numpify_dict_items(user_response_raw) + + try: + last_request.response = user_response + new_request = method.iterate(last_request) + if isinstance( + new_request, tuple + ): # For methods that return mutliple object from an iterate call (e.g., NIMBUS (for now) and EA methods) + new_request = new_request[0] + + method_query.method_pickle = method + method_query.last_request = new_request + db.session.commit() + except Exception as e: + print(f"DEBUG: {e}") + # error, could not iterate, internal server error + if isinstance(last_request, tuple): + last_request_dump = [ + json.dumps(r.content, cls=NumpyEncoder, ignore_nan=True) + for r in last_request + ] + else: + last_request_dump = json.dumps( + last_request.content, cls=NumpyEncoder, ignore_nan=True + ) + return { + "message": "Could not iterate the method with the given response", + "last_request": last_request_dump, + }, 400 + + # we dump the response first so that we can have it encoded into valid JSON using a custom encoder + # ignore_nan=True will ensure np.nan is coverted to valid JSON value 'null'. + + response = json.dumps(new_request.content, cls=NumpyEncoder, ignore_nan=True) + + # ok + # We will deserialize the response into a Python dict here because flask-restx will automatically + # serialize the response into valid JSON. + return {"response": json.loads(response)}, 200 + + +class Intermediate(Resource): + @jwt_required + @role_required(USER_ROLE, GUEST_ROLE) + def post(self): + pass + + +class Save(Resource): + @jwt_required + @role_required(USER_ROLE, GUEST_ROLE) + def post(self): + pass