From 40bf6b21d1f03d550b837f41f65b6518f284e95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edu=20G=C3=B3mez=20Escandell?= Date: Fri, 5 Jan 2024 20:48:59 +0100 Subject: [PATCH 1/3] Part 1 --- 2023/data/24/example.txt | 5 + 2023/data/24/input.txt | 300 +++++++++++++++++++++++++++ 2023/solvelib/24/day24.cpp | 240 +++++++++++++++++++++ 2023/solvelib/24/day24.hpp | 16 ++ 2023/solvelib/24/day24_test.hpp | 27 +++ 2023/solvelib/CMakeLists.txt | 1 + 2023/solvelib/alldays.hpp | 2 + 2023/test/test.cpp | 1 + 2023/xmaslib/matrix/dense_vector.hpp | 5 + 9 files changed, 597 insertions(+) create mode 100644 2023/data/24/example.txt create mode 100644 2023/data/24/input.txt create mode 100644 2023/solvelib/24/day24.cpp create mode 100644 2023/solvelib/24/day24.hpp create mode 100644 2023/solvelib/24/day24_test.hpp diff --git a/2023/data/24/example.txt b/2023/data/24/example.txt new file mode 100644 index 0000000..cbe1492 --- /dev/null +++ b/2023/data/24/example.txt @@ -0,0 +1,5 @@ +19, 13, 30 @ -2, 1, -2 +18, 19, 22 @ -1, -1, -2 +20, 25, 34 @ -2, -2, -4 +12, 31, 28 @ -1, -2, -1 +20, 19, 15 @ 1, -5, -3 \ No newline at end of file diff --git a/2023/data/24/input.txt b/2023/data/24/input.txt new file mode 100644 index 0000000..d8d5146 --- /dev/null +++ b/2023/data/24/input.txt @@ -0,0 +1,300 @@ +277884961010842, 175505292281521, 178142491715369 @ 254, 319, -117 +283566174834691, 323964410438583, 66367418575791 @ 127, -467, 561 +292968982192924, 251621777313874, 229787798929295 @ 24, 26, 5 +325006807232388, 279854404838739, 237875036704901 @ -52, -21, 14 +331644578534356, 338678098724971, 374203537734425 @ -56, -55, -121 +306403740498700, 423836689928945, 336992613890057 @ -20, -128, -13 +313282226223436, 222808574308399, 161325952351421 @ -14, -24, 26 +308467751112024, 239729422033957, 149082309153079 @ -10, 32, 192 +295705405799395, 290314664150320, 224423943828539 @ 15, -58, 29 +276323162696180, 186036298832555, 207596318735801 @ 74, 189, 41 +314754354515938, 211008844196059, 146085274459931 @ -17, -39, 20 +318856238352308, 204758603119539, 140029596035711 @ -48, 117, 194 +499193848343193, 291054337307629, 427138933261816 @ -253, 47, -108 +243613671647428, 262386326933080, 160900581230216 @ 48, 88, 216 +307973727799663, 160150000860559, 275813935638971 @ -19, 221, 9 +409099230240644, 300701918358651, 252725273366801 @ -168, 9, 71 +245363744864656, 347801812052413, 420550317481490 @ 36, 15, -30 +333708714489008, 371739959266639, 302632490840461 @ -69, -202, -108 +308638826201036, 202137318594207, 166485209479584 @ 24, 117, -38 +281267323012404, 175144070305135, 177400745437781 @ 216, 314, -94 +280831414778980, 190983630348395, 330452293039465 @ 19, 169, -42 +269082098297950, 399112184859157, 267752547567959 @ 19, -60, 100 +440110774813126, 518024056807711, 258480606780617 @ -209, -297, 67 +313977355109980, 194608878366451, 175040526960917 @ -28, 165, 153 +310609933859503, 248395392344794, 84312165202331 @ 5, -206, 569 +252747951563500, 312104959994899, 97037720072657 @ 189, -244, 364 +277084043018296, 185131378252315, 377932722126077 @ 9, 173, -12 +109362490600379, 262771024342795, 141730013456159 @ 267, 65, 233 +286873262414584, 244760963012399, 129973414407149 @ 97, -54, 248 +310308593068036, 324489743694949, 241398319627949 @ -24, -24, 89 +226622125329658, 276206331976039, 427972577139081 @ 109, 35, -221 +352725435172432, 406647635763307, 273287549258501 @ -105, -255, -34 +285508401601324, 278341299863155, 214905162197129 @ 41, -36, 45 +329854898231892, 375110610931435, 338582547806937 @ -48, -43, 12 +318169264704202, 196475852174059, 319169424581331 @ -35, 161, 6 +388089075045532, 146305889585209, 457411224005600 @ -104, 211, -76 +315564642593339, 251574058051112, 305222366627142 @ -31, -36, -378 +323353343176483, 215864799439564, 123247627331531 @ -99, -12, 305 +346201065265044, 157581283728881, 220369877716889 @ -64, 202, 155 +321232980504586, 243177499261375, 187077988468444 @ -50, 5, 58 +310371145159419, 210374049133005, 138770121469555 @ 57, -65, 97 +306060249638332, 384004038359799, 435867486091209 @ -20, -69, -125 +277618343657491, 326893919532037, 344414526902910 @ 19, -13, -36 +305375537306301, 257084645713089, 238946486076948 @ -13, 51, 52 +125472286079336, 126162559969981, 114471695488627 @ 366, 308, 282 +434598720936004, 421866841106971, 338533597468873 @ -179, -118, -8 +255145191204908, 363282642834859, 80647688065121 @ 99, -199, 356 +338604117180151, 453730428596362, 87918235469861 @ -65, -212, 311 +431712993903863, 511937636846369, 532223606917116 @ -187, -261, -288 +280519697314666, 237465754883110, 251936125560137 @ 74, 38, -117 +324475312574983, 120075663503044, 129299668674521 @ -59, 400, 251 +336595811008114, 239783293058635, 139224290543903 @ -55, 113, 240 +256686975271060, 309180810414427, 248634330340793 @ 84, -60, 17 +330583256675595, 95904345119423, 92018851404268 @ -49, 277, 294 +295222007157459, 287740595282715, 152115854451685 @ 15, -47, 199 +315039527739234, 336511257207655, 97107621540361 @ -31, -13, 291 +273778132938363, 13859071981894, 355467334115766 @ 53, 530, -206 +264402962836675, 348407328738616, 201875859579375 @ 97, -220, 69 +341986677794707, 305886423400520, 412024330604845 @ -59, 48, -41 +266301461290312, 199735251360064, 382229045508509 @ 44, 156, -137 +307328650626388, 219627852528259, 154403178637121 @ 64, -100, -32 +277715682674656, 186489778158053, 162889190364723 @ 10, 172, 214 +345465632665131, 399235762333297, 409241849161864 @ -103, -325, -420 +279104395528574, 256745855261655, 220117481546241 @ 57, 15, 31 +259983151955008, 192413221122235, 160785059326157 @ 133, 173, 158 +300380532150754, 92987366119093, 247062428668103 @ -6, 335, 53 +353116467505976, 437763907246255, 514772049338639 @ -70, -85, -142 +309114911316460, 298912542324563, 329686770574777 @ -23, 24, -17 +336783046038778, 186196845587293, 315083195131625 @ -87, 188, -237 +287987809363042, 82361864174296, 270292754490074 @ 82, 628, -326 +317389234135652, 218973534412116, 155369944229351 @ -48, -72, -19 +301272656913380, 357674973720610, 305070462225280 @ -16, -16, 58 +224585044536268, 304327733715619, 375976279790089 @ 133, -34, -195 +222740419878996, 373841399560427, 9148813993433 @ 147, -180, 482 +198575339622628, 342199816812649, 351765839542901 @ 104, -8, -7 +344826929465289, 366671549007367, 341427638640673 @ -79, -115, -93 +290175295231624, 217122683617117, 178219638670235 @ 106, 50, -12 +251353036339105, 304282192006747, 264699297869147 @ 169, -175, -171 +307198429850104, 300226640983867, 318788956570212 @ -20, 17, -12 +291953632991513, 355110073123197, 301312679342261 @ -7, -5, 71 +487782734095809, 346321613111503, 454926033788582 @ -211, 5, -88 +313916028457320, 231630252872791, 117507369705959 @ -6, -313, 410 +320045754776822, 340807187573627, 249163877011491 @ -49, -423, -234 +259888849966510, 170591685040227, 40798656047816 @ 262, 297, 716 +226896278552949, 231823285869453, 180002954712996 @ 275, 39, 76 +391920157511824, 436945425316759, 372392546251505 @ -119, -114, -27 +296901766181463, 300281095968024, 269474632921846 @ -7, 24, 66 +259328655430093, 260935495830479, 215548487651421 @ 217, -123, -129 +278025429157336, 399388795118488, 157663843494710 @ 20, -118, 212 +331993131053320, 172727613739159, 214793327040161 @ -100, 261, -109 +216467983121800, 188630351190181, 353332307880815 @ 82, 170, -6 +394821320187837, 487734947368162, 351642535817515 @ -189, -418, -191 +277247316298486, 258966253557367, 370990485789374 @ 10, 93, -12 +302382626562952, 259887555370897, 401367758368217 @ 6, -18, -517 +130050402029788, 225273910841668, 316951534831199 @ 168, 130, 49 +383081561382313, 411873003963709, 221527730904896 @ -145, -201, 96 +390849762993160, 175138099376698, 199132314193157 @ -148, 194, 143 +318243091337748, 258393907144439, 203961149002001 @ -48, -252, -247 +251477178647958, 123196327251711, 484804390932939 @ 33, 235, -108 +319116084630682, 229799289992609, 159108998504933 @ -59, -114, 5 +326523319061306, 337767106383251, 221303276066553 @ -45, -11, 139 +237261593562328, 310933314539329, 311235784225286 @ 60, 27, 38 +308547600159577, 339283257866560, 452440513672151 @ -25, 24, -59 +322534993244230, 242958362232835, 227546792207843 @ -51, 29, -28 +317751661407964, 221748007671541, 171737816585387 @ -36, 108, 162 +349625665566228, 338357466098347, 262735948436649 @ -72, -7, 93 +305416340766840, 300010877385057, 347542563543747 @ -18, 22, -42 +184523426884804, 282199218778793, 347255888020600 @ 112, 67, 12 +255980223672439, 321290555266886, 280720640765192 @ 121, -158, -136 +205765220813324, 443344440202004, 337316806783314 @ 104, -144, -6 +299165864896058, 126250740504459, 394838372175196 @ 6, 321, -354 +283884554469478, 168659011450704, 481449035278696 @ 22, 208, -344 +190423819173616, 411987150607363, 222923429469317 @ 110, -83, 145 +368997391217119, 305484674856148, 330800825753534 @ -209, -202, -420 +300329702762030, 319680236350549, 337378184172593 @ -15, 26, 23 +400314877286680, 300392857721647, 391219138797389 @ -171, -10, -180 +191745659674060, 131471787332211, 278513544788763 @ 136, 249, 49 +275213821774274, 130493251730578, 184033327057663 @ 210, 554, -75 +320923024676886, 267577592804231, 235589515636972 @ -46, -35, -42 +316806852104090, 344704422895367, 291966087193359 @ -33, 7, 82 +280379840423146, 140447920771075, 198887551560674 @ 206, 537, -216 +318244371370690, 218702332283221, 165613354486673 @ -55, -52, -97 +269954695392876, 357764417062385, 11876194655405 @ 36, -78, 425 +277895252764838, 279204838187054, 508031448678966 @ 18, 52, -248 +293800495688148, 428280535977389, 302894855356361 @ 32, -512, -253 +367854641023429, 164861740894038, 547421785603831 @ -83, 192, -159 +352625227420860, 170562037319481, 207041113238255 @ -120, 223, 65 +448384746065844, 327816808533643, 516125773021241 @ -253, -58, -394 +179498955449660, 267864231678493, 231558698775467 @ 180, 50, 92 +290250477233586, 269362690665456, 266171136375923 @ 14, 30, 5 +501445073822564, 468814633642667, 382985108946649 @ -231, -131, -21 +366104032225510, 246735555481981, 373519353762311 @ -103, 90, -94 +384608195893581, 355961795748631, 307276736141797 @ -151, -115, -57 +134662228018066, 365777159571973, 299591042197569 @ 151, -10, 79 +399423700224192, 454262828734187, 366947037690889 @ -115, -95, 15 +339928259984588, 268727645375059, 258148699882971 @ -72, 41, 37 +296288174886540, 276759010827835, 528656919413817 @ -13, 83, -137 +249994745963504, 365115028032079, 346924509900823 @ 50, -49, -20 +320643864913336, 207744327990163, 207344297474945 @ -55, 107, -123 +278469915149543, 147113418895509, 254821284725691 @ 21, 231, 73 +228230259834796, 261109181825299, 318890768984825 @ 151, 26, -145 +299608985494205, 169691276388017, 165885304315232 @ 185, 519, -238 +303569553970038, 287800177783831, 223078949273803 @ -7, -25, 60 +284136600336904, 131391567192655, 552347521053647 @ 6, 239, -256 +315844328917588, 314811166081047, 472853805823841 @ -32, 37, -109 +380055010633258, 518839682828239, 389418450726776 @ -130, -331, -146 +311365316745873, 317409180810364, 377436942987532 @ -27, 26, -26 +260751066137068, 311523547980439, 184392931455041 @ 70, -52, 149 +317972085320884, 227446528710923, 190295352235673 @ -41, 30, -7 +318900882376913, 299787359099244, 377491809571711 @ -37, -8, -155 +194268350240188, 7425205330702, 10763089464056 @ 168, 472, 446 +325494216221237, 199403346075166, 198366839600638 @ -121, 134, -386 +130548616339360, 297457113526215, 301850173509273 @ 157, 58, 75 +282139611364620, 289163825444721, 475539039900465 @ 12, 40, -201 +329559979325292, 329223754334337, 392346249707987 @ -60, -110, -286 +286535022848376, 304207355563595, 284559776500617 @ 42, -111, -141 +239176440909323, 154510271369535, 474708679911757 @ 63, 213, -177 +291611694163668, 142938635857259, 93091603955001 @ 140, 541, 508 +216426225874420, 380146584914827, 372789768500585 @ 86, -57, -38 +340211613901630, 251527866397265, 334165360947763 @ -86, 39, -203 +265094359174367, 352868616076638, 198692484445864 @ 17, 10, 184 +54605735571868, 281506453145411, 54513718422609 @ 223, 78, 324 +234318830544479, 287687548373676, 293157848572948 @ 69, 48, 48 +325989283017300, 354673730166443, 132469966830681 @ -64, -338, 241 +340084148304254, 317674949107389, 308301411837593 @ -58, 31, 59 +366582419679940, 275567581891843, 185260798191821 @ -100, 55, 176 +322205716724548, 194001979138019, 182099187472289 @ -122, 196, -496 +352549165621854, 256961287306441, 372792317797187 @ -103, 44, -220 +337418662714879, 254764403135161, 332931099954215 @ -89, 7, -287 +321684420627280, 185151771907705, 207357479818697 @ -114, 320, -845 +327717760557496, 238116478629511, 308571763293977 @ -103, -88, -821 +162739345288297, 294351184174519, 337634303932643 @ 187, 21, -47 +253861200754993, 350086213272664, 353516897506169 @ 83, -124, -165 +319931107490212, 244495500402391, 219208797272249 @ -56, -121, -277 +322237913038243, 167917843101800, 228187103073985 @ -47, 228, 19 +286603555309888, 218503901625193, 147234009820577 @ 118, 48, 159 +274654054472604, 146879399270915, 455459392851129 @ 17, 220, -137 +305463599936748, 406166577587027, 248678051954181 @ -22, -41, 136 +323710518616899, 263657364200607, 202008773462747 @ -69, -155, -91 +468316261743205, 431444676190348, 370897707161489 @ -239, -158, -77 +302584938867640, 434197773783841, 448472129162555 @ -18, -90, -86 +196970441380141, 121629330391222, 219311171995057 @ 211, 314, 67 +284202846688544, 325368360665900, 252143070269633 @ 36, -116, -13 +286064449104784, 103075320033901, 9503333973014 @ 12, 299, 428 +300404183943604, 273354907357021, 159214949561615 @ 16, -78, 158 +305237795806282, 167013260198209, 206098825091570 @ 22, 311, -140 +366229085615878, 332434719455159, 337236759810321 @ -95, -9, -9 +285574822743613, 135498151330834, 385493749915121 @ 37, 300, -333 +41673376819363, 156304284101059, 20836434877421 @ 241, 201, 359 +297750934744546, 42370046631253, 293076081447746 @ 26, 655, -274 +306487292963398, 271332139807579, 517616660773406 @ -22, 81, -164 +350216164881906, 417095078363635, 453833747779477 @ -75, -115, -155 +319555386830152, 282757948641172, 301863861608747 @ -36, 68, 65 +257146158598591, 213077354890543, 321995682347996 @ 67, 133, -74 +304027306177296, 249652454505373, 220496257213731 @ 14, -46, -104 +361601492593396, 487737797879683, 221693941481441 @ -84, -170, 146 +281548916337546, 105300243119801, 418719491910973 @ 9, 270, -95 +300225256122108, 267096374170765, 81773061453989 @ 108, -472, 677 +448769503339908, 294270801927623, 316344378397357 @ -172, 58, 54 +111869859833982, 169408150115571, 13295231281001 @ 179, 189, 371 +264224078112440, 185101898606823, 226415733748613 @ 27, 174, 140 +319910411208859, 250218852893467, 195064130081165 @ -55, -143, -121 +260694301359368, 231307448526619, 164856923284426 @ 44, 113, 202 +253696324928929, 100706796847273, 417625654392398 @ 29, 255, -32 +51670511701000, 203738362613003, 171059103698449 @ 259, 153, 205 +295079170372060, 213274632121003, 153409028783561 @ 235, -55, -59 +253807221444157, 178912835446421, 153944546985884 @ 187, 223, 164 +295374038615278, 224569560933781, 224168876144537 @ 113, -38, -421 +352070607517528, 308643144431651, 344510597838609 @ -167, -257, -551 +197472085567828, 465409282240619, 380581097539801 @ 82, -98, 9 +312165004723432, 206287383358475, 247957873936052 @ -20, 129, -136 +307012626299613, 244167046311124, 226801665576965 @ -7, 26, -25 +319835099153194, 166069983712299, 184220268583575 @ -53, 321, -38 +425776282733351, 554511114601544, 510531581907167 @ -141, -194, -127 +333377779100430, 294755454514726, 109920592156643 @ -70, -52, 293 +280367354547058, 220802920313851, 194678664300212 @ 38, 113, 122 +311501004885268, 239474760094027, 154708114263593 @ -12, -37, 134 +263353035117916, 419563850822665, 451746187729649 @ 24, -77, -93 +297761457553030, 362509489248637, 497532685552793 @ -10, -41, -197 +334277912879960, 240872230449631, 184340792618505 @ -103, -10, 39 +323512903262376, 225780761277356, 106293945640157 @ -60, 54, 335 +314790955819978, 206892541694869, 145100265138671 @ -14, -17, -19 +404031059661172, 492101824553119, 338743154190533 @ -120, -134, 42 +215739952417672, 42051271371863, 151027750395433 @ 97, 360, 223 +270798024336859, 258770370032911, 48417270486818 @ 237, -211, 734 +272993913429708, 220627904539955, 228829497375915 @ 188, 37, -260 +256357760241420, 232711325479339, 128091819564345 @ 165, 41, 255 +248743484993113, 461300516195987, 463909210377903 @ 43, -135, -123 +303383918582992, 241125655873028, 396160123340452 @ -20, 118, -6 +353058711937532, 320285241836565, 328969146800759 @ -84, -12, -28 +266412174964476, 310346349673192, 320849265242830 @ 24, 32, 34 +421969737659317, 427848364926297, 287053654641956 @ -143, -81, 86 +311216506167548, 272504368781859, 278051114211521 @ -25, 46, 26 +263638601153860, 190468050169503, 190206351065537 @ 220, 190, -43 +299361036118648, 270400922908699, 269657404326101 @ 100, -431, -873 +314978081442568, 376655326978219, 354524012179721 @ -31, -47, -9 +255189587715953, 227407353663339, 152014990080711 @ 219, 33, 157 +433070873934442, 298800717739618, 523697451485462 @ -150, 58, -146 +338505757295488, 261845357110309, 174622525430321 @ -58, 86, 199 +343835415011923, 276860509675739, 285475574677785 @ -227, -399, -837 +224918783892404, 275196626054923, 188492808724473 @ 117, 32, 154 +189024738820668, 417890382425239, 443230129406241 @ 90, -52, -51 +303562465525444, 389915200600327, 200432127487355 @ -8, -217, 112 +285274970994444, 216928731935587, 185600068878297 @ 107, 68, -5 +279865572444166, 444900599252449, 401710253401859 @ 10, -129, -67 +363119320076126, 289475834781019, 309874634903035 @ -93, 41, 18 +276494328515428, 246366031255369, 189027347856371 @ 24, 90, 166 +241197388269688, 440907991158359, 304939529022521 @ 70, -173, 11 +289079769495700, 233277121379155, 271068194362334 @ 32, 73, -88 +322806407815692, 199482204425513, 156277724404674 @ -120, 123, -90 +128813048287852, 258819612383971, 274768442497649 @ 184, 89, 83 +305549959176484, 196904784246605, 197499868209335 @ -8, 160, 92 +83541000854470, 280859539718354, 148161904713834 @ 202, 76, 232 +158920080018588, 48237447310059, 10593133529521 @ 239, 417, 456 +301817678402140, 221641313392951, 159965777154373 @ 70, -22, 28 +298236142755294, 214664527990055, 150874534137112 @ 150, -27, 28 +327078640527340, 195441112946845, 181775729483231 @ -108, 168, -104 +335885489881483, 555435312994045, 436597470120911 @ -77, -645, -439 +256993001165358, 258948800095657, 349313093963627 @ 98, 23, -235 +255643267162018, 252756844792057, 142459900779227 @ 183, -40, 204 +137122560698884, 29058774113767, 204664269730601 @ 300, 472, 111 +205616926032202, 282415861203343, 369371215636760 @ 86, 69, -6 +311300945599604, 252700220734111, 288886007718709 @ -24, 62, -30 +249686973576562, 167072583133603, 133383456041251 @ 49, 197, 246 +244944505592545, 390431690695441, 152932943116202 @ 55, -77, 222 +346218428016218, 550984980225212, 285075405480352 @ -102, -656, -108 +323344730309860, 256479063312235, 285870547738199 @ -40, 97, 84 +337439672310474, 201989556870115, 167895601546913 @ -126, 137, 83 +331269371981756, 124824039230827, 285042845419185 @ -63, 305, -62 +214863431658481, 237658005804868, 292900005016091 @ 147, 88, -39 +341991423677957, 134808175852434, 149033325097441 @ -85, 286, 211 +245841400910212, 325647921711479, 100131782004781 @ 52, 6, 286 +280251602048812, 274132710796843, 268974157447445 @ 34, 17, -8 +268493955591317, 315298487124890, 252589319976887 @ 21, 28, 113 +327368735378805, 427850474203108, 75223607587272 @ -45, -100, 312 +254628461671252, 317516316956587, 337990125196121 @ 56, -13, -49 +342351590820436, 276549872505579, 292761117075417 @ -80, 16, -45 +301509004597636, 355359030053527, 162151453574411 @ 40, -637, 86 +287224987598008, 196991515981619, 189116670351481 @ 190, 157, -213 +280767298479012, 341622185023339, 241788076632713 @ 26, -79, 65 +493169511921778, 391078873522247, 390285963660175 @ -227, -53, -36 +273493248573433, 546578116352407, 213060694244072 @ 13, -211, 162 +310966272678685, 200631233414606, 268956612106818 @ -5, 138, -522 +229223355256930, 102051187192621, 8732637768470 @ 190, 403, 560 +374733308713035, 341834726352694, 354419566120407 @ -111, -34, -51 +370955593729804, 454682333609071, 132361405608533 @ -86, -92, 248 +223475291985512, 398777052778817, 336154272508325 @ 110, -150, -67 +283795790494765, 302675910869296, 155064179955614 @ 19, -8, 210 +253175177118088, 238805016108809, 327202253304521 @ 82, 84, -109 +293622634725574, 241174662330409, 182938240862141 @ 55, -14, 41 +333191929575892, 313778675673067, 318471123472217 @ -53, 19, 22 +369161188627828, 250385121436635, 362116622742569 @ -122, 70, -142 +508534863558052, 504402883021075, 388109504417105 @ -236, -165, -23 +302210813315774, 207521985252901, 151391934832205 @ 105, 50, 29 +165793968623187, 26284503920678, 181666237367869 @ 117, 330, 199 +304100772841297, 128423450296065, 338274743468007 @ 7, 387, -443 +252208158100908, 395566158014815, 324753621897181 @ 38, -58, 36 +315253407088972, 312296530582795, 253984174512497 @ -31, -35, 40 +319690234947588, 350312093374059, 263906379724521 @ -37, -39, 76 +327009249338848, 187121459388679, 156155828606741 @ -106, 223, 73 \ No newline at end of file diff --git a/2023/solvelib/24/day24.cpp b/2023/solvelib/24/day24.cpp new file mode 100644 index 0000000..7335eb1 --- /dev/null +++ b/2023/solvelib/24/day24.cpp @@ -0,0 +1,240 @@ +#include "day24.hpp" +#include "xmaslib/iota/iota.hpp" +#include "xmaslib/log/log.hpp" +#include "xmaslib/matrix/dense_algebra.hpp" +#include "xmaslib/matrix/dense_matrix.hpp" +#include "xmaslib/matrix/dense_vector.hpp" +#include "xmaslib/parsing/parsing.hpp" +#include "xmaslib/line_iterator/line_iterator.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using Float = double; +using Vector = xmas::basic_vector; +using Matrix = xmas::basic_matrix; + +constexpr bool almost_zero(Float v) { + return std::abs(v) < 1e-8; +} + +struct line { + // Defined as x=p+ku + Vector origin; + Vector director; +}; + +auto determinant3(Matrix const& A) { + assert(A.nrows() == 3); + assert(A.ncols() == 3); + + Float r = 0; + Float sign = 1; + for (std::size_t i = 0; i < 3; ++i) { + auto j = (i + 1) % 3; + auto k = (j + 1) % 3; + + r += sign * A[i][i] * (A[j][j] * A[k][k] - A[j][k] * A[k][j]); + r *= -1; + } + + return r; +} + +bool coplanar(Vector const& u, Vector const& v, Vector const& w) { + Matrix M(3, 3); + M[0][0] = u[0]; + M[1][0] = u[1]; + M[2][0] = u[2]; + + M[0][1] = v[0]; + M[1][1] = v[1]; + M[2][1] = v[2]; + + M[0][2] = w[0]; + M[1][2] = w[1]; + M[2][2] = w[2]; + + auto d = determinant3(M); + return almost_zero(d); +} + +std::optional intersection_with_YZ_plane(line const& A, Float x) { + if (almost_zero(A.director[0] - x)) { + return {}; + } + return {(x - A.origin[0]) / A.director[0]}; +} + +std::optional intersection_with_XZ_plane(line const& A, Float y) { + if (almost_zero(A.director[1] - y)) { + return {}; + } + return {(y - A.origin[1]) / A.director[1]}; +} + +bool sorted(Float x, Float y, Float z) { + return (x <= y && y <= z); +} + +bool line_enters_region_2D(line const& A, Float min, Float max) { + if (sorted(min, A.origin[0], max) && sorted(min, A.origin[1], max)) { + return true; + } + + auto k = intersection_with_YZ_plane(A, min); + if (k.has_value() && *k > 0) { + return true; + } + + k = intersection_with_YZ_plane(A, max); + if (k.has_value() && *k > 0) { + return true; + } + + k = intersection_with_XZ_plane(A, min); + if (k.has_value() && *k > 0) { + return true; + } + + k = intersection_with_XZ_plane(A, max); + if (k.has_value() && *k > 0) { + return true; + } + + return false; +} + +/* +Algorithm +--------- +This works in 3D as well, I didn't read the problem statement properly. Good thing is that what +works for 3D also works for 2D. +--- +We need to: +- Find the intercept of two lines A:p+λu and B:q+κv +- This intercept may or may not exist +- Only intercepts in the future (κ>0 and λ>0) are accepted + +Solution +1. Define plane Π:p+λu+αw, where w := q - p +2. x,p and q must draw a triangle embedded inside Π. + Hence the edge vectors (x-p), (x-q), (q-p) must as well. + These magnitues have names: λu, κv, and w. + λ amd κ are scalars so we can pull them out. u,w,w must be coplanar + We check this by ascertaining det[(u v w)] == 0 +3. We define a basis for Π via Gramm-Schmitt, with origin at p + O = p + î = u / ||u|| + ĵ = w / || w || - (w · î)/||w|| î +4. Translate the two lines to this new basis (O, ξ, η) + A: ξ = λu·î η = κu·ĵ + B: ξ = w·î + κv·î η = w·ĵ + κv·ĵ +5. Find the intercept by setting A(λ)=B(κ) + λu·î = w·î + κv·î } + λu·ĵ = w·ĵ + κv·ĵ } +6. Note that u and ĵ are perpendicular (thanks Gramm-Schmitt), so the second equation becomes: + 0 = w·ĵ + κv·ĵ +6. Hence, + κ = - (w·ĵ)/(v·ĵ) + λ = (w + κv)·î / (u·î) +7. If κ or λ are negative, the intercepts are in the past +8. Ortherwise, we now know the intercept point to be: + x = q+κv +*/ +std::optional find_intercept(line const& A, line const& B) { + Vector const& u = A.director; + Vector const& v = B.director; + Vector const w = B.origin - A.origin; + + if (!coplanar(u, v, w)) { + return {}; + } + + // Define a basis for the plane containing A and B + Vector i = A.director.normalized(); + Vector j = (w - xmas::algebra::inner(w, i) * i).normalized(); + + // Find intercept of A:p+λu and B:q+κv + Float kappa = -xmas::algebra::inner(w, j) / xmas::algebra::inner(v, j); + Float lambda = xmas::algebra::inner(w + kappa * v, i) / xmas::algebra::inner(u, i); + + if (kappa < 0 || lambda < 0) { + return {}; + } + + return {B.origin + kappa * B.director}; +} + +line parse_line_2D(std::string_view text) { + auto ints = xmas::parse_ints(text); + assert(ints.size() == 6); + + return { + .origin = {Float(ints[0]), Float(ints[1]), Float(0.0)}, + .director = {Float(ints[3]), Float(ints[4]), Float(0.0)}, + }; +} +} + +std::uint64_t Day24::part1_generalized(std::int64_t min_xy, std::int64_t max_xy) { + xmas::views::linewise in(this->input); + + auto min = Float(min_xy); + auto max = Float(max_xy); + + std::vector lines; + std::transform(in.cbegin(), in.cend(), std::back_inserter(lines), parse_line_2D); + + xmas::views::iota iota(lines.size()); + + return std::transform_reduce(std::execution::par_unseq, iota.begin(), iota.end(), + std::uint64_t{0}, std::plus{}, + [iota, &lines, min, max](std::size_t i) -> std::uint64_t { + if (!line_enters_region_2D(lines[i], min, max)) { + return 0; + } + + return std::transform_reduce(iota.begin() + std::ptrdiff_t(i) + 1, iota.end(), + std::uint64_t{0}, std::plus{}, + [&i, &lines, min, max](std::size_t j) -> std::uint64_t { + auto intersect = find_intercept(lines[i], lines[j]); + if (!intersect.has_value()) { + return 0; + } + + Vector x = *intersect; + + if (x[0] < min || x[0] > max) { + return 0; + } + + if (x[1] < min || x[1] > max) { + return 0; + } + + xlog::debug("Detected in-bounds intersection between lines {} and {}", i, j); + return 1; + }); + }); +} + +std::uint64_t Day24::part1() { + return part1_generalized(200000000000000, 400000000000000); +} + +std::uint64_t Day24::part2() { + throw std::runtime_error("Not implemented"); +} \ No newline at end of file diff --git a/2023/solvelib/24/day24.hpp b/2023/solvelib/24/day24.hpp new file mode 100644 index 0000000..c238d3b --- /dev/null +++ b/2023/solvelib/24/day24.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "xmaslib/solution/solution.hpp" + +class Day24 : public xmas::solution { +public: + int day() override { + return 24; + } + +public: + std::uint64_t part1_generalized(std::int64_t min, std::int64_t max); + + std::uint64_t part1() override; + std::uint64_t part2() override; +}; diff --git a/2023/solvelib/24/day24_test.hpp b/2023/solvelib/24/day24_test.hpp new file mode 100644 index 0000000..8a41155 --- /dev/null +++ b/2023/solvelib/24/day24_test.hpp @@ -0,0 +1,27 @@ +#include "day24.hpp" +#include + +TEST_CASE("Day 24") { + + SUBCASE("Part 1, example") { + Day24 solution{}; + solution.set_input("./data/24/example.txt"); + solution.load(); + REQUIRE_EQ(solution.part1_generalized(7, 27), 2); + } + + SUBCASE("Part 2, example") { + Day24 solution{}; + solution.set_input("./data/24/example.txt"); + solution.load(); + REQUIRE_EQ(solution.part2(), 47); + } + + SUBCASE("Real data") { + Day24 solution{}; + solution.set_input("./data/24/input.txt"); + solution.load(); + REQUIRE_EQ(solution.part1(), 27732); + REQUIRE_EQ(solution.part2(), 0); + } +} \ No newline at end of file diff --git a/2023/solvelib/CMakeLists.txt b/2023/solvelib/CMakeLists.txt index 72ea22e..dccae86 100644 --- a/2023/solvelib/CMakeLists.txt +++ b/2023/solvelib/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(solvelib 21/day21.cpp 22/day22.cpp 23/day23.cpp + 24/day24.cpp ) set_target_properties(solvelib PROPERTIES LINKER_LANGUAGE CXX) diff --git a/2023/solvelib/alldays.hpp b/2023/solvelib/alldays.hpp index 50b7e31..7411792 100644 --- a/2023/solvelib/alldays.hpp +++ b/2023/solvelib/alldays.hpp @@ -25,6 +25,7 @@ #include "21/day21.hpp" #include "22/day22.hpp" #include "23/day23.hpp" +#include "24/day24.hpp" inline void populate_registry() { xmas::register_solution(); @@ -50,4 +51,5 @@ inline void populate_registry() { xmas::register_solution(); xmas::register_solution(); xmas::register_solution(); + xmas::register_solution(); } diff --git a/2023/test/test.cpp b/2023/test/test.cpp index d47cec6..76971f1 100644 --- a/2023/test/test.cpp +++ b/2023/test/test.cpp @@ -24,6 +24,7 @@ #include "solvelib/21/day21_test.hpp" #include "solvelib/22/day22_test.hpp" #include "solvelib/23/day23_test.hpp" +#include "solvelib/24/day24_test.hpp" #include "xmaslib/iota/iota_test.hpp" #include "xmaslib/lru/lru_test.hpp" diff --git a/2023/xmaslib/matrix/dense_vector.hpp b/2023/xmaslib/matrix/dense_vector.hpp index 3235293..41959f8 100644 --- a/2023/xmaslib/matrix/dense_vector.hpp +++ b/2023/xmaslib/matrix/dense_vector.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,10 @@ class basic_vector { basic_vector(basic_vector const& other) : m_data(other.data()) { } + basic_vector(std::initializer_list&& data) : + m_data(std::forward>(data)) { + } + basic_vector(basic_vector&& other) { std::swap(m_data, other.m_data); } From bb297e89e116130542de7d49ae94d743cfe7af88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edu=20G=C3=B3mez=20Escandell?= Date: Sun, 21 Jan 2024 20:33:01 +0100 Subject: [PATCH 2/3] Improvements in algebra that I did not end up using --- 2023/solvelib/08/day08.cpp | 6 +- 2023/solvelib/17/day17.cpp | 12 +- 2023/solvelib/21/day21.cpp | 6 +- 2023/solvelib/22/day22.cpp | 4 +- 2023/solvelib/23/day23.cpp | 4 +- 2023/xmaslib/matrix/algebra_test.hpp | 6 +- 2023/xmaslib/matrix/dense_algebra.hpp | 95 +++++++-- 2023/xmaslib/matrix/dense_matrix.hpp | 282 +++++++++++++++++++------- 2023/xmaslib/matrix/dense_vector.hpp | 18 +- 2023/xmaslib/view/view.hpp | 3 + 10 files changed, 333 insertions(+), 103 deletions(-) diff --git a/2023/solvelib/08/day08.cpp b/2023/solvelib/08/day08.cpp index 9712415..2738651 100644 --- a/2023/solvelib/08/day08.cpp +++ b/2023/solvelib/08/day08.cpp @@ -141,7 +141,7 @@ auto finishing_nodes(std::map const& network) { auto timings_matrix(std::string_view instr, std::map const& network, std::span sources, std::span destinations) { - xmas::basic_matrix timing_matrix(sources.size(), destinations.size(), 0); + xmas::dense_matrix timing_matrix(sources.size(), destinations.size(), 0); xmas::views::iota rows(0, timing_matrix.nrows()); xmas::views::iota cols(0, timing_matrix.ncols()); @@ -156,7 +156,7 @@ auto timings_matrix(std::string_view instr, std::map const& n } std::uint64_t compute_permutation( - xmas::basic_matrix timings, std::vector selected) { + xmas::dense_matrix timings, std::vector selected) { assert(selected.size() == timings.nrows()); std::vector t(selected.size()); @@ -169,7 +169,7 @@ std::uint64_t compute_permutation( } std::uint64_t find_best_permutation( - xmas::basic_matrix timings, std::vector& selected_finishers) { + xmas::dense_matrix timings, std::vector& selected_finishers) { std::size_t row = selected_finishers.size(); if (row == timings.nrows()) { return compute_permutation(timings, selected_finishers); diff --git a/2023/solvelib/17/day17.cpp b/2023/solvelib/17/day17.cpp index 00cc4bc..e06bbd2 100644 --- a/2023/solvelib/17/day17.cpp +++ b/2023/solvelib/17/day17.cpp @@ -147,7 +147,7 @@ void possible_moves(xmas::views::text_matrix map, state s, std::size_t min_steps using queue = std::priority_queue, bool (*)(state const&, state const&)>; -[[maybe_unused]] auto fmt_curr_state(std::array, 4> const& visited, +[[maybe_unused]] auto fmt_curr_state(std::array, 4> const& visited, state s) { return xmas::lazy_string([&visited, s] { std::stringstream ss; @@ -254,11 +254,11 @@ std::uint64_t solve(std::string& input, std::size_t min_steps, std::size_t max_s // choice of heuristic such that I can short-circuit once I've found a solution. auto max_heat = std::numeric_limits::max(); - std::array, 4> visited{ - xmas::basic_matrix(map.nrows(), map.ncols(), max_heat), - xmas::basic_matrix(map.nrows(), map.ncols(), max_heat), - xmas::basic_matrix(map.nrows(), map.ncols(), max_heat), - xmas::basic_matrix(map.nrows(), map.ncols(), max_heat), + std::array, 4> visited{ + xmas::dense_matrix(map.nrows(), map.ncols(), max_heat), + xmas::dense_matrix(map.nrows(), map.ncols(), max_heat), + xmas::dense_matrix(map.nrows(), map.ncols(), max_heat), + xmas::dense_matrix(map.nrows(), map.ncols(), max_heat), }; heap queue; diff --git a/2023/solvelib/21/day21.cpp b/2023/solvelib/21/day21.cpp index 5d8029d..8d79bea 100644 --- a/2023/solvelib/21/day21.cpp +++ b/2023/solvelib/21/day21.cpp @@ -45,7 +45,7 @@ coords find_start(xmas::views::text_matrix map) { constexpr auto sentinel = std::numeric_limits::max(); -void bfs(xmas::views::text_matrix map, xmas::basic_matrix& distances, std::size_t d, +void bfs(xmas::views::text_matrix map, xmas::dense_matrix& distances, std::size_t d, coords pos, std::back_insert_iterator> enqueuer) { if (distances[pos.row][pos.col] != sentinel) { return; @@ -80,7 +80,7 @@ void bfs(xmas::views::text_matrix map, xmas::basic_matrix& distance } [[maybe_unused]] auto fmt_map( - xmas::views::text_matrix map, xmas::basic_matrix& distance) { + xmas::views::text_matrix map, xmas::dense_matrix& distance) { return xmas::lazy_string([map, &distance]() -> std::string { std::stringstream ss; for (std::size_t i = 0; i < map.nrows(); ++i) { @@ -101,7 +101,7 @@ void bfs(xmas::views::text_matrix map, xmas::basic_matrix& distance std::pair count_parities( xmas::views::text_matrix map, std::size_t nsteps, coords start) { - xmas::basic_matrix distance(map.nrows(), map.ncols(), sentinel); + xmas::dense_matrix distance(map.nrows(), map.ncols(), sentinel); std::vector queue{start}; for (std::size_t s = 0; s <= nsteps; ++s) { diff --git a/2023/solvelib/22/day22.cpp b/2023/solvelib/22/day22.cpp index 6cd044b..6fc5bb8 100644 --- a/2023/solvelib/22/day22.cpp +++ b/2023/solvelib/22/day22.cpp @@ -106,7 +106,7 @@ std::vector parse(std::string_view input) { return blocks; } -[[maybe_unused]] auto fmt_map(xmas::basic_matrix& map, std::span) { +[[maybe_unused]] auto fmt_map(xmas::dense_matrix& map, std::span) { return xmas::lazy_string([&map] { std::stringstream ss; for (auto r : map.rows()) { @@ -127,7 +127,7 @@ void simulate_drop(std::span blocks) { auto max_x = rng::max(blocks | v::transform([](block const& b) { return b.upper.x; })); auto max_y = rng::max(blocks | v::transform([](block const& b) { return b.upper.y; })); - xmas::basic_matrix map(max_x + 1, max_y + 1, placeholder_id); + xmas::dense_matrix map(max_x + 1, max_y + 1, placeholder_id); xlog::debug("Detected {} rows and {} columns", map.nrows(), map.ncols()); for (block& b : blocks) { diff --git a/2023/solvelib/23/day23.cpp b/2023/solvelib/23/day23.cpp index 77c39cf..4bf1500 100644 --- a/2023/solvelib/23/day23.cpp +++ b/2023/solvelib/23/day23.cpp @@ -139,7 +139,7 @@ enum BOOL : std::uint8_t { }; std::array::iterator explore(xmas::views::text_matrix map, - xmas::basic_matrix& visited, std::array::iterator it, temp_edge tip, + xmas::dense_matrix& visited, std::array::iterator it, temp_edge tip, heading towards) { tip.step(towards); while (map.at(tip.pos) == char(towards)) { @@ -185,7 +185,7 @@ void find_all_nodes(xmas::views::text_matrix map, graph& g) { graph build_graph(xmas::views::text_matrix map) { graph g; - xmas::basic_matrix visited(map.nrows(), map.ncols(), FALSE); + xmas::dense_matrix visited(map.nrows(), map.ncols(), FALSE); // Start point assert(map.at(0, 1) == '.'); diff --git a/2023/xmaslib/matrix/algebra_test.hpp b/2023/xmaslib/matrix/algebra_test.hpp index 077a30a..6b0da26 100644 --- a/2023/xmaslib/matrix/algebra_test.hpp +++ b/2023/xmaslib/matrix/algebra_test.hpp @@ -9,7 +9,7 @@ TEST_CASE("QR decomoposion") { SUBCASE("Wikipedia example") { - xmas::matrix A(3, 3); + xmas::dense_matrix A(3, 3); // clang-format off A[0][0] = 12; A[0][1] = -51; A[0][2] = 4; @@ -35,7 +35,7 @@ TEST_CASE("QR decomoposion") { } SUBCASE("Example") { - xmas::matrix A(3, 3); + xmas::dense_matrix A(3, 3); // clang-format off A[0][0] = 4; A[0][1] = 2; A[0][2] = 1; @@ -61,7 +61,7 @@ TEST_CASE("QR decomoposion") { } SUBCASE("Example 2") { - xmas::matrix A(3, 3); + xmas::dense_matrix A(3, 3); // clang-format off A[0][0] = 0; A[0][1] = 0; A[0][2] = 1; diff --git a/2023/xmaslib/matrix/dense_algebra.hpp b/2023/xmaslib/matrix/dense_algebra.hpp index 78fe1a0..f3e85fc 100644 --- a/2023/xmaslib/matrix/dense_algebra.hpp +++ b/2023/xmaslib/matrix/dense_algebra.hpp @@ -1,14 +1,14 @@ #pragma once -#include "../log/log.hpp" - -#include +#include "xmaslib/log/log.hpp" +#include "xmaslib/matrix/dense_matrix.hpp" +#include #include #include #include #include #include -#include +#include namespace xmas { @@ -16,7 +16,7 @@ template class basic_vector; template -class basic_matrix; +class dense_matrix; namespace algebra { @@ -37,8 +37,8 @@ T inner(basic_vector const& lhs, basic_vector const& rhs) { } template -basic_matrix outter(auto const& lhs, auto const& rhs) { - basic_matrix out(lhs.size(), rhs.size()); +dense_matrix outter(auto const& lhs, auto const& rhs) { + dense_matrix out(lhs.size(), rhs.size()); for (std::size_t i = 0; i < lhs.size(); ++i) { for (std::size_t j = 0; j < rhs.size(); ++j) { out[i][j] = lhs[i] * rhs[j]; @@ -57,9 +57,47 @@ auto outter(basic_vector const& lhs, basic_vector const& rhs) { return outter(lhs.data(), rhs.data()); } +template +basic_vector MV_mult(Matrix const& A, Vector const& u) { + assert(A.ncols() == u.size()); + basic_vector out(A.nrows()); + std::transform(std::execution::par_unseq, A.crows().begin(), A.crows().end(), out.begin(), + [&u](auto const& row) { return inner(row, u); }); + return out; +} +} + +// Matrix-vector product +template +auto operator*(Matrix const& A, Vector const& u) + requires(!std::same_as) +{ + using T = decltype(*u.begin()); + return algebra::MV_mult(A, u); +} + +template +auto operator*(Matrix const& A, basic_vector const& u) + requires(is_matrix) +{ + return algebra::MV_mult(A, u); +} + +// Vector-matrix product +template +basic_vector operator*(auto const& u, is_matrix auto const& A) { + return algebra::MV_mult(A.transpose(), u); +} + +template +basic_vector operator*(basic_vector const& u, is_matrix auto const& A) { + return algebra::MV_mult(A.transpose(), u); +} + +namespace algebra { // Gram–Schmidt QR decomposition. Returns Q. To obtain R, do R = QA template -std::pair, basic_matrix> qr_decompose(basic_matrix const& A) { +std::pair, dense_matrix> qr_decompose(dense_matrix const& A) { assert(A.nrows() == A.ncols()); // A must be square const std::size_t N = A.nrows(); @@ -74,8 +112,8 @@ std::pair, basic_matrix> qr_decompose(basic_matrix const& basis.push_back(u.normalized()); } - basic_matrix Q(N, N); - basic_matrix R(N, N); + dense_matrix Q(N, N); + dense_matrix R(N, N); for (std::size_t r = 0; r != N; ++r) { for (std::size_t c = 0; c != N; ++c) { @@ -89,7 +127,7 @@ std::pair, basic_matrix> qr_decompose(basic_matrix const& // Solve system Ax=b, where A is an upper triangular matrix template -basic_vector triangularSolve(basic_matrix const& A, basic_vector const& b) { +basic_vector triangularSolve(dense_matrix const& A, basic_vector const& b) { assert(A.nrows() == A.ncols()); // A must be square assert(A.nrows() == b.size()); // b must be the same size as A const std::size_t N = A.nrows(); @@ -105,7 +143,7 @@ basic_vector triangularSolve(basic_matrix const& A, basic_vector const& // Solve system Ax=b with QR decomposition template -basic_vector QRsolve(basic_matrix const& A, basic_vector const& b) { +basic_vector QRsolve(is_matrix auto const& A, basic_vector const& b) { assert(A.nrows() == A.ncols()); // A must be square assert(A.nrows() == b.size()); // b must be the same size as A auto [Q, R] = xmas::algebra::qr_decompose(A); @@ -115,7 +153,7 @@ basic_vector QRsolve(basic_matrix const& A, basic_vector const& b) { // Solve system Ax=b with Gaussian elimination template -basic_vector GaussSolve(basic_matrix A, basic_vector b) { +basic_vector GaussSolve(dense_matrix A, basic_vector b) { assert(A.nrows() == A.ncols()); // A must be square assert(A.nrows() == b.size()); // b must be the same size as A const std::size_t N = A.nrows(); @@ -150,5 +188,36 @@ basic_vector GaussSolve(basic_matrix A, basic_vector b) { return triangularSolve(A, b); } +// Solve system Ax=b with the conjugate gradients method. +template +bool CGsolve(is_matrix auto const& A, xmas::basic_vector const& b, xmas::basic_vector& x, + T epsilon = 1e-8) { + + auto r = b - A * x; + T err = r.norm2(); + if (err < epsilon) { + return true; + } + + auto p = r; + for (std::size_t k = 0; k < x.size(); ++k) { + T alpha = err / xmas::algebra::inner(p, A * p); + x += alpha * p; + r -= alpha * (A * p); + + T new_err = r.norm2(); + if (new_err < epsilon) { + return true; + } + + T beta = new_err / err; + p = r + beta * p; + + err = new_err; + } + + return false; +} + } } diff --git a/2023/xmaslib/matrix/dense_matrix.hpp b/2023/xmaslib/matrix/dense_matrix.hpp index 12f723a..4874374 100644 --- a/2023/xmaslib/matrix/dense_matrix.hpp +++ b/2023/xmaslib/matrix/dense_matrix.hpp @@ -4,14 +4,16 @@ #include "../view/view.hpp" #include "../lazy_string/lazy_string.hpp" -#include "dense_algebra.hpp" #include "dense_vector.hpp" +#include "xmaslib/iota/iota.hpp" #include #include #include #include #include +#include +#include #include #include #include @@ -20,22 +22,39 @@ namespace xmas { template -class basic_matrix { +class base_matrix { }; + +template +concept is_matrix = std::derived_from>; + +template +class transposed_view; + +template +class dense_matrix : public base_matrix { public: - basic_matrix(std::size_t nrows, std::size_t ncols) : + dense_matrix(std::size_t nrows, std::size_t ncols) : m_data(nrows * ncols), n_rows(nrows), n_cols(ncols) { } - basic_matrix(std::size_t nrows, std::size_t ncols, T const& value) : + dense_matrix(std::size_t nrows, std::size_t ncols, T const& value) : m_data(nrows * ncols, value), n_rows(nrows), n_cols(ncols) { } template - basic_matrix(Iterator begin, Iterator end, std::size_t nrows, std::size_t ncols) : + dense_matrix(Iterator begin, Iterator end, std::size_t nrows, std::size_t ncols) : m_data(begin, end), n_rows(nrows), n_cols(ncols) { assert(end - begin == n_rows * n_cols); } + dense_matrix(transposed_view view) : dense_matrix(view.nrows(), view.ncols()) { + for (std::size_t i = 0; i < n_rows; ++i) { + for (std::size_t j = 0; j < n_rows; ++j) { + *this[i][j] = view[i][j]; + } + } + } + std::size_t size() const noexcept { return data().size(); } @@ -179,7 +198,7 @@ class basic_matrix { std::ranges::views::transform([this](std::size_t r) { return ccol(r); }); } - basic_matrix& transpose() { + dense_matrix& transpose() { std::vector d(data().size()); xmas::view v(d.begin(), d.end()); for (auto c : cols()) { @@ -191,73 +210,69 @@ class basic_matrix { return *this; } - [[nodiscard]] basic_matrix transposed() const { - auto out = basic_matrix(ncols(), nrows()); - xmas::view v(out.begin(), out.end()); - for (auto c : cols()) { - elementwise(c, v, [](T t) { return t; }); - v.pop_front(nrows()); - } - return out; + [[nodiscard]] transposed_view transposed() const { + return transposed_view{*this}; } - basic_matrix& operator+=(basic_matrix const& other) { + dense_matrix& operator+=(dense_matrix const& other) { elementwise(m_data, other.m_data, m_data, [](T t, T o) { return t + o; }); return *this; } - basic_matrix& operator-=(basic_matrix const& other) { + dense_matrix& operator-=(dense_matrix const& other) { elementwise(m_data, other.m_data, m_data, [](T t, T o) { return t - o; }); return *this; } - basic_matrix operator+(basic_matrix const& other) { - basic_matrix out(n_rows, n_cols); + dense_matrix operator+(dense_matrix const& other) { + dense_matrix out(n_rows, n_cols); elementwise(m_data, other.m_data, out, [](T t, T o) { return t + o; }); return out; } - basic_matrix operator-(basic_matrix const& other) { - basic_matrix out(n_rows, n_cols); + dense_matrix operator-(dense_matrix const& other) { + dense_matrix out(n_rows, n_cols); elementwise(m_data, other.m_data, out, [](T t, T o) { return t - o; }); return out; } - basic_matrix operator*(basic_matrix const& other) const { + dense_matrix operator*(is_matrix auto const& other) const { assert(n_cols == other.n_rows); - basic_matrix out(n_rows, other.n_cols); - for (std::size_t r = 0; r < out.n_rows; ++r) { - for (std::size_t c = 0; c < out.n_cols; ++c) { - out[r][c] = algebra::inner(row(r), other.col(c)); + dense_matrix out(n_rows, other.n_cols); + xmas::views::iota iota(out.nrows()); + std::for_each(std::execution::par_unseq, iota.begin(), iota.end(), [&](std::size_t r) { + for (std::size_t c = 0; c < out.ncols(); ++c) { + out[r][c] = std::transform_reduce(std::execution::unseq, row(r).begin(), row(r).end(), + other.col(c).begin(), T{0}, std::plus{}, std::multiplies{}); } - } + }); return out; } - basic_matrix& operator*=(T a) { + dense_matrix& operator*=(T a) { elementwise(data(), data(), [a](T t) { return a * t; }); return *this; } - basic_matrix operator*(T a) const { - auto out = basic_matrix(nrows(), ncols()); + dense_matrix operator*(T a) const { + auto out = dense_matrix(nrows(), ncols()); elementwise(cdata(), out.data(), [a](T t) { return a * t; }); return out; } - basic_matrix& operator/=(T a) { - elementwise(data(), data(), [a](T t) { return a / t; }); + dense_matrix& operator/=(T k) { + elementwise(data(), data(), [k](T t) { return t / k; }); return *this; } - basic_matrix operator/(T k) const { - auto out = basic_matrix(size()); - elementwise(cdata(), out.data(), [k](T t) { return k / t; }); + dense_matrix operator/(T k) const { + auto out = dense_matrix(nrows(), ncols()); + elementwise(cdata(), out.data(), [k](T t) { return t / k; }); return out; } - static basic_matrix identity(std::size_t n) { - basic_matrix out(n, n); + static dense_matrix identity(std::size_t n) { + dense_matrix out(n, n, T{0}); for (std::size_t i = 0; i < n; ++i) { out[i][i] = T{1}; } @@ -266,7 +281,7 @@ class basic_matrix { template , typename TupleLike2 = std::pair> - basic_matrix submatrix(TupleLike1 const& row_range, TupleLike2 const& col_range) { + dense_matrix submatrix(TupleLike1 const& row_range, TupleLike2 const& col_range) { auto const [r0, r1] = row_range; auto const [c0, c1] = col_range; @@ -276,7 +291,7 @@ class basic_matrix { assert(r1 <= n_rows); assert(c1 <= n_cols); - basic_matrix B(r1 - r0, c1 - c0); + dense_matrix B(r1 - r0, c1 - c0); for (std::size_t r = r0; r < r1; ++r) { for (std::size_t c = c0; c < c1; ++c) { B[r - r0][c - c0] = (*this)[r][c]; @@ -286,7 +301,7 @@ class basic_matrix { return B; } - auto format(std::string_view fmt = "{:>4}") const { + auto format(std::string_view fmt = "{}") const { return lazy_string([this, fmt] { std::stringstream ss; for (auto r : crows()) { @@ -315,43 +330,174 @@ class basic_matrix { assert(in.size() <= out.size()); std::transform(std::execution::unseq, in.begin(), in.end(), out.begin(), op); } -}; -using matrix = basic_matrix; + static T inner_product(auto const& in_left, auto const& in_right) { + return std::transform_reduce(std::execution::unseq, in_left.begin(), in_left.end(), + in_right.begin(), T{0}, std::plus{}, std::multiplies{}); + } +}; -template -basic_matrix operator*(T k, basic_matrix const& A) { +template +dense_matrix operator*(T k, Matrix const& A) + requires is_matrix +{ return A * k; } -// Matrix-vector product template -basic_vector operator*(basic_matrix const& A, auto const& u) { - assert(A.ncols() == u.size()); - basic_vector out(A.nrows()); - std::transform(A.crows().begin(), A.crows().end(), out.begin(), - [&u](auto const& row) { return algebra::inner(row, u); }); - return out; -} +class transposed_view : public base_matrix { + dense_matrix base; -// Vector-matrix product -template -basic_vector operator*(auto const& u, basic_matrix const& A) { - assert(A.nrows() == u.size()); - basic_vector out(A.ncols()); - std::transform(A.cols().begin(), A.cols().end(), out.begin(), - [&u](auto const& col) { return algebra::inner(u, col); }); - return out; -} +public: + explicit transposed_view(dense_matrix const& base) : base(base) { + } -template -basic_vector operator*(basic_matrix const& A, basic_vector const& u) { - return A * u.cdata(); -} + std::size_t size() const noexcept { + return base.size(); + } -template -basic_vector operator*(basic_vector const& u, basic_matrix const& A) { - return u.data() * A; -} + std::size_t nrows() const noexcept { + return base.ncols(); + } + std::size_t ncols() const noexcept { + return base.nrows(); + } + + auto row(std::size_t r) { + return base.col(r); + } + + auto row(std::size_t r) const { + return base.col(r); + } + + auto col(std::size_t c) const { + return base.row(c); + } + + auto crow(std::size_t r) const { + return base.ccol(r); + } + + auto ccol(std::size_t r) const { + return base.crow(r); + } + + auto operator[](std::size_t r) { + return base.col(r); + } + + auto operator[](std::size_t r) const { + return base.col(r); + } + + template + std::enable_if, T>::type operator[](TupleLike rc) const { + auto const& [r, c] = rc; + return row(c)[r]; + } + + template + std::enable_if, T&>::type operator[](TupleLike rc) { + auto const& [r, c] = rc; + return row(c)[r]; + } + + auto begin() { + return base.begin(); + } + auto begin() const { + return base.begin(); + } + auto cbegin() const { + return base.begin(); + } + + auto end() { + return base.end(); + } + auto end() const { + return cend(); + } + auto cend() const { + return base.cend(); + } + + auto rows() noexcept { + return base.cols(); + } + + auto rows() const noexcept { + return base.cols(); + } + + auto crows() const noexcept { + return base.ccols(); + } + + auto cols() noexcept { + return base.rows(); + } + + auto cols() const noexcept { + return base.rows(); + } + + auto ccols() const noexcept { + return base.crows(); + } + + [[nodiscard]] dense_matrix transposed() const { + return dense_matrix{base}; + } + + dense_matrix operator+(is_matrix auto const& other) { + dense_matrix out(*this); + return out += other; + } + + dense_matrix operator-(is_matrix auto const& other) { + dense_matrix out(*this); + return out -= other; + } + + dense_matrix operator*(is_matrix auto const& other) const { + assert(ncols() == other.nrows()); + dense_matrix out(nrows(), other.ncols()); + + xmas::views::iota iota(out.nrows()); + std::for_each(std::execution::par_unseq, iota.begin(), iota.end(), [&](std::size_t r) { + for (std::size_t c = 0; c < out.ncols(); ++c) { + out[r][c] = std::transform_reduce(std::execution::unseq, row(r).begin(), row(r).end(), + other.col(c).begin(), T{0}, std::plus{}, std::multiplies{}); + } + }); + return out; + } + + dense_matrix operator*(T a) const { + dense_matrix out(*this); + return out *= a; + } + + dense_matrix operator/(T k) const { + dense_matrix out(*this); + return out /= k; + } + + auto format(std::string_view fmt = "{}") const { + return lazy_string([this, fmt] { + std::stringstream ss; + for (auto r : crows()) { + ss << '['; + for (T t : r) { + ss << ' ' << std::vformat(fmt, std::make_format_args(t)); + } + ss << " ]\n"; + } + return std::move(ss).str(); + }); + } +}; } diff --git a/2023/xmaslib/matrix/dense_vector.hpp b/2023/xmaslib/matrix/dense_vector.hpp index 41959f8..61ad63a 100644 --- a/2023/xmaslib/matrix/dense_vector.hpp +++ b/2023/xmaslib/matrix/dense_vector.hpp @@ -1,11 +1,10 @@ #pragma once -#include "dense_algebra.hpp" - #include "../lazy_string/lazy_string.hpp" #include #include +#include #include #include #include @@ -114,6 +113,18 @@ class basic_vector { return *this; } + basic_vector operator+() const { + basic_vector out(size()); + elementwise(m_data, m_data, [](T t) { return -t; }); + return out; + } + + basic_vector operator-() const { + basic_vector out(size()); + elementwise(m_data, m_data, [](T t) { return -t; }); + return out; + } + basic_vector operator+(basic_vector const& other) const { basic_vector out(size()); elementwise(m_data, other.m_data, out, [](T t, T o) { return t + o; }); @@ -161,7 +172,8 @@ class basic_vector { } auto norm2() const { - return algebra::inner(*this, *this); + return std::transform_reduce( + std::execution::unseq, begin(), end(), begin(), T{0}, std::plus{}, std::multiplies{}); } void normalize() { diff --git a/2023/xmaslib/view/view.hpp b/2023/xmaslib/view/view.hpp index e6fa3cb..000c8ff 100644 --- a/2023/xmaslib/view/view.hpp +++ b/2023/xmaslib/view/view.hpp @@ -19,6 +19,9 @@ class view { view(It begin, It end) : m_begin(begin), m_end(end) { } + view(auto& container) : m_begin(std::begin(container)), m_end(std::end(container)) { + } + auto begin() const { return m_begin; } From 86faca7f81852ca5f5415ffae82f3714e5564481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edu=20G=C3=B3mez=20Escandell?= Date: Sun, 21 Jan 2024 20:33:18 +0100 Subject: [PATCH 3/3] Part 2 --- 2023/solvelib/24/day24.cpp | 227 +++++++++++++++++++++++++------- 2023/solvelib/24/day24_test.hpp | 2 +- 2 files changed, 179 insertions(+), 50 deletions(-) diff --git a/2023/solvelib/24/day24.cpp b/2023/solvelib/24/day24.cpp index 7335eb1..4a18e9b 100644 --- a/2023/solvelib/24/day24.cpp +++ b/2023/solvelib/24/day24.cpp @@ -1,84 +1,63 @@ #include "day24.hpp" + #include "xmaslib/iota/iota.hpp" #include "xmaslib/log/log.hpp" -#include "xmaslib/matrix/dense_algebra.hpp" -#include "xmaslib/matrix/dense_matrix.hpp" -#include "xmaslib/matrix/dense_vector.hpp" #include "xmaslib/parsing/parsing.hpp" #include "xmaslib/line_iterator/line_iterator.hpp" +#include "xmaslib/matrix/dense_algebra.hpp" +#include "xmaslib/matrix/dense_vector.hpp" #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include namespace { -using Float = double; +using Float = long double; +using Int = std::int64_t; using Vector = xmas::basic_vector; -using Matrix = xmas::basic_matrix; + +struct Line { + // Defined as x(t) = origin + t * director + xmas::basic_vector origin{}; + xmas::basic_vector director{}; +}; constexpr bool almost_zero(Float v) { return std::abs(v) < 1e-8; } -struct line { - // Defined as x=p+ku - Vector origin; - Vector director; -}; - -auto determinant3(Matrix const& A) { - assert(A.nrows() == 3); - assert(A.ncols() == 3); - - Float r = 0; - Float sign = 1; +bool coplanar(Vector const& u, Vector const& v, Vector const& w) { + Float determinant = 0; for (std::size_t i = 0; i < 3; ++i) { auto j = (i + 1) % 3; auto k = (j + 1) % 3; - - r += sign * A[i][i] * (A[j][j] * A[k][k] - A[j][k] * A[k][j]); - r *= -1; + determinant += u[i] * (v[j] * w[k] - v[k] * w[j]); } - return r; + return almost_zero(determinant); } -bool coplanar(Vector const& u, Vector const& v, Vector const& w) { - Matrix M(3, 3); - M[0][0] = u[0]; - M[1][0] = u[1]; - M[2][0] = u[2]; - - M[0][1] = v[0]; - M[1][1] = v[1]; - M[2][1] = v[2]; - - M[0][2] = w[0]; - M[1][2] = w[1]; - M[2][2] = w[2]; - - auto d = determinant3(M); - return almost_zero(d); -} - -std::optional intersection_with_YZ_plane(line const& A, Float x) { +std::optional intersection_with_YZ_plane(Line const& A, Float x) { if (almost_zero(A.director[0] - x)) { return {}; } return {(x - A.origin[0]) / A.director[0]}; } -std::optional intersection_with_XZ_plane(line const& A, Float y) { +std::optional intersection_with_XZ_plane(Line const& A, Float y) { if (almost_zero(A.director[1] - y)) { return {}; } @@ -89,7 +68,7 @@ bool sorted(Float x, Float y, Float z) { return (x <= y && y <= z); } -bool line_enters_region_2D(line const& A, Float min, Float max) { +bool line_enters_region_2D(Line const& A, Float min, Float max) { if (sorted(min, A.origin[0], max) && sorted(min, A.origin[1], max)) { return true; } @@ -154,7 +133,7 @@ Solution 8. Ortherwise, we now know the intercept point to be: x = q+κv */ -std::optional find_intercept(line const& A, line const& B) { +std::optional> find_intercept(Line const& A, Line const& B) { Vector const& u = A.director; Vector const& v = B.director; Vector const w = B.origin - A.origin; @@ -171,14 +150,27 @@ std::optional find_intercept(line const& A, line const& B) { Float kappa = -xmas::algebra::inner(w, j) / xmas::algebra::inner(v, j); Float lambda = xmas::algebra::inner(w + kappa * v, i) / xmas::algebra::inner(u, i); - if (kappa < 0 || lambda < 0) { + return { + {lambda, kappa} + }; +} + +std::optional find_future_intercept(Line const& A, Line const& B) { + auto opt = find_intercept(A, B); + + if (!opt.has_value()) { + return {}; + } + + auto [lambda, kappa] = *opt; + if (lambda < 0 || kappa < 0) { return {}; } return {B.origin + kappa * B.director}; } -line parse_line_2D(std::string_view text) { +Line parse_line_2D(std::string_view text) { auto ints = xmas::parse_ints(text); assert(ints.size() == 6); @@ -187,6 +179,7 @@ line parse_line_2D(std::string_view text) { .director = {Float(ints[3]), Float(ints[4]), Float(0.0)}, }; } + } std::uint64_t Day24::part1_generalized(std::int64_t min_xy, std::int64_t max_xy) { @@ -195,7 +188,7 @@ std::uint64_t Day24::part1_generalized(std::int64_t min_xy, std::int64_t max_xy) auto min = Float(min_xy); auto max = Float(max_xy); - std::vector lines; + std::vector lines; std::transform(in.cbegin(), in.cend(), std::back_inserter(lines), parse_line_2D); xmas::views::iota iota(lines.size()); @@ -210,7 +203,7 @@ std::uint64_t Day24::part1_generalized(std::int64_t min_xy, std::int64_t max_xy) return std::transform_reduce(iota.begin() + std::ptrdiff_t(i) + 1, iota.end(), std::uint64_t{0}, std::plus{}, [&i, &lines, min, max](std::size_t j) -> std::uint64_t { - auto intersect = find_intercept(lines[i], lines[j]); + auto intersect = find_future_intercept(lines[i], lines[j]); if (!intersect.has_value()) { return 0; } @@ -235,6 +228,142 @@ std::uint64_t Day24::part1() { return part1_generalized(200000000000000, 400000000000000); } +namespace { + +Line parse_line_3D(std::string_view text) { + auto ints = xmas::parse_ints(text); + assert(ints.size() == 6); + + return { + .origin = {Float(ints[0]), Float(ints[1]), Float(ints[2])}, + .director = {Float(ints[3]), Float(ints[4]), Float(ints[5])}, + }; +} + +template +U cast_with_warning(T t) { + U u = static_cast(t + 0.5); + if (std::isnan(t)) { + xlog::warning("Bad conversion from {} to {}: NaN", typeid(T).name(), typeid(U).name()); + } else if (std::abs(static_cast(u) - t) > 0.05) { + xlog::warning("Bad conversion from {} to {}: {} != {}", typeid(T).name(), typeid(U).name(), + (long double)t, u); + } + return u; +} + +// closest_point finds the closest point in a line to the origin. +Vector closest_point(Line const& l) { + auto vu = xmas::algebra::inner(l.origin, l.director); + auto uu = l.director.norm2(); + return l.origin - (vu / uu) * l.director; +} + +Vector cross_product_3D(Vector u, Vector v) { + assert(u.size() == 3); + assert(v.size() == 3); + + return { + +(u[1] * v[2] - u[2] * v[1]), + -(u[0] * v[2] - u[2] * v[0]), + +(u[0] * v[1] - u[1] * v[0]), + }; +} + +std::optional solve_part_2(Line const& reference, Line L1, Line L2) { + // Use first line as reference + L1.origin -= reference.origin; + L1.director -= reference.director; + + L2.origin -= reference.origin; + L2.director -= reference.director; + + // Find planes defined by origin and each line + auto n1 = cross_product_3D(L1.director, closest_point(L1)).normalized(); + auto n2 = cross_product_3D(L2.director, closest_point(L2)).normalized(); + + // Find line intersecting both planes + auto u = cross_product_3D(n1, n2); + if (almost_zero(u.norm2())) { + // Lines are coplanar + return {}; + } + u.normalize(); + + // Define a solution trajectory + // This trajectory coincides with the solution's, but starts at the wrong spot + // and moves at the wrong speed. + Line traj{ + .origin = {0, 0, 0}, + .director = u, + }; + + // Find collision times + auto opt = find_intercept(traj, L1); + if (!opt.has_value()) { + return {}; + } + auto [k1, t1] = *opt; + + opt = find_intercept(traj, L2); + if (!opt.has_value()) { + return {}; + } + auto [k2, t2] = *opt; + + // Scale director vector so speed is correct + auto dk = k2 - k1; + auto dt = t2 - t1; + traj.director *= dk / dt; + + // Find collision point with line 1 + auto collision = L1.origin + t1 * L1.director; + + // We know collision point and velocity: rewind time to find the origin. + traj.origin = collision - t1 * traj.director; + + // Undo change of reference + return { + { + .origin = traj.origin + reference.origin, + .director = traj.director + reference.director, + } + }; +} +} + std::uint64_t Day24::part2() { - throw std::runtime_error("Not implemented"); -} \ No newline at end of file + xmas::views::linewise in(this->input); + + std::vector lines; + std::transform(in.begin(), in.end(), std::back_inserter(lines), parse_line_3D); + + // Solve + std::optional solution; + // Looks O(n³) but we shortcut after very few iterations + for (std::size_t i = 0; i < lines.size() && !solution.has_value(); ++i) { + for (std::size_t j = i + 1; j < lines.size() && !solution.has_value(); ++j) { + for (std::size_t k = j + 1; k < lines.size(); ++k) { + solution = solve_part_2(lines[i], lines[j], lines[k]); + + if (solution.has_value()) { + xlog::debug("Found solution with lines {}, {}, {}", i, j, k); + break; + } + // Otherwise, the lines were coplanar, making the system indeterminate + } + } + } + + if (!solution.has_value()) { + throw std::runtime_error("System is indeterminate"); + } + + xlog::debug("Start position is {}", solution->origin.format("{:.2f}")); + xlog::debug("Velocity is {}", solution->director.format("{:.2f}")); + + // Generate answer + auto u = solution->origin; + return std::transform_reduce(u.begin(), u.end(), std::uint64_t{0}, std::plus{}, + cast_with_warning); +} diff --git a/2023/solvelib/24/day24_test.hpp b/2023/solvelib/24/day24_test.hpp index 8a41155..7ae540a 100644 --- a/2023/solvelib/24/day24_test.hpp +++ b/2023/solvelib/24/day24_test.hpp @@ -22,6 +22,6 @@ TEST_CASE("Day 24") { solution.set_input("./data/24/input.txt"); solution.load(); REQUIRE_EQ(solution.part1(), 27732); - REQUIRE_EQ(solution.part2(), 0); + REQUIRE_EQ(solution.part2(), 641619849766168); } } \ No newline at end of file