Ce s-a întâmplat la reforma numerelor din anul 2021?

 Cum ziceam ultima dată prin luna mai din 2021, pe la sfârșitul primei decade de atunci din lună îmi venise în cap un plan nou pentru rapidizarea algoritmilor de căutare numerică, astfel ca numerele de fond 1 să poată fi obținute mai ușor, tot cu ajutorul bine dozat al numerelor de manevră (numite și de fond 2), însă fără aceeași goană după adunat munți de terabaiți de date în fondul 2, ca în 2018-2019, ci cu generarea limitată a acestor numere (care nu erau până la urmă scopul ultim al cercetărilor) și ștergerea lor din când în când, cu reînprospătare.


Bineînțeles că nici abordarea asta nu era una ideală - urmăream mai departe obținerea numerelor unele din altele, dar tot cu folosirea unor valori „străine” precum cele din fondul 2, pe măsura înțelegerii pe care o aveam până atunci despre cum este optim să caut numerele. În luna aprilie mai cumpărasem un hard disk de 18 TB pentru acumularea de spațiu potențial de depozitare în casă (pe lângă un SSD portabil primit cadou de la serviciu, tot prin primele luni din acel an, cu 250 de GB), și aceste dispozitive merseseră, bineînțeles, la calculatorul-rege din casă, mutat între timp în sufragerie la mine, numit THREADRIPPER, după numele procesorului de flagship din 2018, care era primul din istoria desktop-urilor care să aibă 64 de unități logice.

În practica programatorică însă, nu aveam nicidecum să ajung să le umplu! În acele zile de mai mi-am schițat într-adevăr planul de lucru, anume cum să re-concep algoritmii din casă ca să calculeze numerele într-o formă nouă, și ce-i drept întrezăream o bună optimizare a strategiei de căutare așa: să se folosească numai numere de fond 1, și să fie obținute unele din altele folosind factori de legătură simultan în ambele direcții (o înmulțire și o împărțire, sau invers), în loc de „numai înmulțire” sau „numai împărțire”, cum le tot foloseam pe la NUMSIMPL, MODPRIME, MODIFSUM și variațiile acestora (dar în mare, mare parte doar cele 3 programe de mai sus, sus sau jos, unde sus înseamnă înmulțirea și jos este împărțirea). Alternativa la asta era generarea aleatorie (cu RandomLib în C) a numerelor unele din altele, atât strict cu fondul 1, cu VECUNSUB, cât și cu ajutorul numerelor de fond 2, cu programe având nume ca SCLEPAMORIS, FACTMSUB, FACTORSUB și variațiile lor în funcție de cât erau de mari numerele și, implicit, de cum erau făcuți factorii lor primi componenți + cât de departe ajungeau puterile acestora.


Astfel, FACTORSUBM/FACTSUBM erau pentru cele mai mari numere, de la 161 la 1910 cifre, unde existau și prime componente mai mari de 64 de biți care, de la 220 de cifre încolo, nu erau neapărat legate în mod trivial de niște numere perfecte (căci la puterile acestea prime, numite Mersenne, se putea aplica o abordare specială, ca pentru puterile lui 2) și, cel mai important, numerele astea așa de mari aveau și factori primi componenți mai mici, dar ale căror puteri maxime depășeau și ele borna de 64 de biți fără semn, pe care în C se reprezintă nativ numerele naturale, cu viteză bună, în tipul de date unsigned long long alias gmp_ui (ca să îl scriu mai scurt), sau uint64_t (dar despre ăsta mai târziu) - și atunci, pentru acele puteri depășitoare de 2^64, aveam alt regim special, cu matrici dedicate de tip mpz_t, și factorii primi ale căror puteri puteau ajunge așa au fost botezați factori de tip K. Așa mi-a venit să le zic, prin codul meu numeric sunt nume de variabile bine definite și totodată criptice dacă ar fi să le citească altcineva, fără a înțelege mai întâi documentația asta.

Pentru numerele mai mici, de dimensiuni medii (53 - 160 de cifre), unde existau factori primi peste 64 de biți, dar în afara lor puterile prime componente stăteau în gama de 64 de biți, existau FACTORSUB și FACTSUB, iar până la 52 de cifre, unde toți factorii primi sunt pe 64 de biți, sunt numerele mici, cu FACTORMSUB și FACTMSUB. Diferența dintre FACTORSUB și FACTSUB fără OR este că la primul se făceau direct sumele de divizori ale numerelor, care aveau de respectat regula cu numitorul fracției ireductibile sumă/număr maxim 10, iar la celălalt se pornea de la numărătorul și numitorul abundențial ale numerelor de pornire, de la care se generau aleator un factor de înmulțire și unul de împărțire (același principiu de generare și la OR-uri), apoi, la sfârșit, se prelucrau numărătorul și numitorul acestea modificate și trebuia ca nm să ajungă egal cu maxim 10. nr și nm erau de obicei mai mici decât sumele, și mai ușor de prelucrat, dar mereu mpz_t, căci nu era greu să ajungă să depășească borna de 2 la puterea 64. Mai încercasem în trecut o variantă (non-aleatorie) în care nr și nm să fie doar pe 64 de biți, dar sigur este posibil doar la o varietate limitată de numere, până la 52 de biți, și foarte probabil nici măcar toate aceste numere.

La fel, pentru versiunea de generare aleatorie numai cu numere de fond 1, era VECUNSUB, cu sumele de divizori modificate, cu alegerea aleatorie a factorilor primi prin care noul număr să difere de cel de plecare, dar într-o singură variație de mărime a numerelor folosite, fără M-uri. Unul pentru toate gamele numerice. Și cu varietatea VECSUB, unde se făceau numărătorul și numitorul abundențial modelate, care avea și variația de mărime VECSUBMED (numere de maxim 160 de cifre).


Așa că de pe la 10 mai 2021 m-am apucat de o nouă rundă de algoritmi numerici și, pe alocuri, și de căutări, iar în noaptea de 13 mai 2021 chiar am mai găsit trei numere noi, care erau sub 160 de cifre, folosind metoda de înmulțire+împărțire - astfel că indexul de fond 1 a fost actualizat de la 30006, cât rămăsese din 12 noiembrie 2019, la 30009, în acea joi cu ploaie și răcoare afară. Am mai făcut și unele căutări numerice cu cantități limitate de fondul 2 numeric, fără a mai ajunge la terabaiții de pe vremuri. De asemenea, orarul de căutări era mult mai limitat decât cel din perioada 2015-2019 sau din anii 2009-2014, și foloseam numai Veritonul (cel mai slab calculator din casă) și, cu măsură, Threadripper-ul, cu CPU-ul setat la frecvența standard de 3 gigaherți și fără overclocking sau turbo boost, plus memoria la 2133 de megaherți în loc de 3333, ca să se consume mai puțin curent electric. Voiam să rămân la două cifre de consum și de factură (sub 100 de kilowați pe lună și sub 100 de lei), ce am și reușit - maxim 91 de kilowați au fost. Perioada de lucru cu numerele din 2021 a durat din mai până în iulie, până la 15 iulie, și au fost trei facturi impactate - 91 cu 91 cu 74 de kilowați.

Iată așadar că NU au fost niște schimbări de o zi-două. Pentru noile programe numerice, m-am concentrat pe preluarea numărătorului și a numitorului abundențial ale numerelor stocate deja (fond 1 cu fond 2), care să fie modificate în timpul căutărilor fără a mai calcula integral sumele divizorilor - începusem din 2019 ceva în direcția aceasta, iar acum, în 2021, eram mai convins - și pe căutarea cu două operații simultane a numerelor, înmulțire și împărțire (sau invers), care se mai cheamă și căutare spiralată, sau în spirală (și pe sus și pe jos, sau invers). Principiul ăsta de spirală avea mai târziu csă ajungă să fie foarte folosit, dar o să ajungem și acolo. Cu răbdarea trecem marea.


Am făcut fișiere noi de tip .cc (sursă de compilare) și headere, și am schimbat forma nomenclaturii - să fie fișiere cu majuscule la nume. Astfel, pentru „numsimpl” au apărut NUMSIMPL.cc și NNUMSIMPL.h, pentru MODPRIME, MODPRIME.cc cu NMODPRIME.h, iar pentru modulele de MODIFSUM am redenumit în MODNUM fișierele și am făcut headere noi de MODNUM.h, în trei variații: MODNUM simplu, pentru factorii de legătură pe 64 de biți, MODNUMMPZ pentru cazurile când numerele trebuiau căutate cu factori de legătură (înmulțitori, împărțitori) peste 64 de biți, dar fără a se divide cu numere prime mai mari ele însele de 64 de biți, și MPZMODNUMMPZ, când factorii de legătură erau meniți a se împărți și la numere prime peste 64 de biți. Aceleași denumiri cu sau fără MPZ s-au regăsit și în numele fișierelor de tip .cc.

De asemenea, am făcut separație între factorii de legătură pari și impari la MODNUM (distincție care era făcută și pe vremuri) și între sursele factorilor de legătură (care puteau fi generați exhaustiv, cu tot felul de puteri prime posibile ale factorilor componenți ai numerelor mari, caz în care spuneam că depozitul de numere de legătură este COEFLEG, sau COEFLEGMPZ, sau MPZCOEFLEGMPZ - unde semnificația silabelor MPZ era aceeași de mai sus - ori să îi generez numai dintre numerele de fond 1, adică doar acei factori cu care numerele deja existente de fond 1 se puteau obține unele din altele, prin înmulțire sau împărțire, și atunci le ziceam VC fișierelor acestora de legătură, putând și ele să aibă numai numere pe 64 de biți, sau mai mari - dar în fișiere separate, și de asemenea respectam o separație între factorii pari și cei impari pentru MODNUM). Am cam robotit ceva ca să fac și combinațiile de căutare par cu impar, sau impar cu par (adică par sus, impar jos, și invers) pentru factorii de legătură pe 64 de biți, sau mpz_t cu divizibilitate cu numere prime H și D*, sau mpz_t cu împărțire la toate tipurile de factori primi componenți ai numerelor.

* H sunt numerele prime, toate pe 64 de biți, care pot să apară la puteri mai mari de 1 în factorizările numerelor de fond 1. Numărul lor poate fi chiar și de 350 dacă se iau toate numerele până la 1910 cifre, sau 22 pentru cele de maxim 52 de cifre, sau 9 pentru cele al căror divizor impar maxim este pe 64 de biți. Puterea maximă o atinge 3 cu 147, spre capătul celor 1910 cifre. Iar D sunt celelalte numere prime pe 64 de biți, care apar doar la puterea-unitate în factorizare. Sunt mai multe decât H-urile.

Pe lângă acestea am umblat și pe la VECUN, care era o căutare a numerelor tot cu înmulțire sau împărțire, la alegere, în sus sau în jos, dar cu calculul integral al sumelor de divizori. Am optimizat funcțiile lui de căutare, pentru numere mari (cu factori K și factori E**), mijlocii și mici. Am despărțit funcțiile sale, de asemenea, după criteriul factori pari/impari.

** Acele numere prime componente care trec de 64 de biți. Pot fi mai multe decât H-urile, dar sunt și mai puține decât D-urile. De la 53 la 220 de biți ele sunt două (până la 70 de cifre) și trei în rest, toate numere prime Mersenne***, de la 221 la 1910 mai apar și altele, maxim câteva sute cu totul pe 643 de biți, mai precis 466 cel mai mult. Prin contrast, D-urile ajung până la 4684 la maxim 1910 cifre. Iar la maxim 52 de cifre, ele sunt 99, H sunt 22 și E 0.

***Numerele prime care adunate cu 1 dau o putere de 2. Primă și ea.


La toate speciile de programe de mai sus, am avut grijă să existe funcții sus/jos (înglobate în NUMSIMPL, VECUN, MODPRIME și fiecare MODNUM în parte), și pe lângă acestea, cu tot cu parități, clase de mărime numerică și dimensiuni de coeficienți de legătură, am introdus și acele programe căutătoare și la înmulțire și la împărțire, cu SPIRAL în nume. Așa că au ieșit zeci de programe noi de sub teascul creației. Toate aceste programe, cu excepția lui VECUN și a fratelui său VECUNSPIRAL, care a respectat aceleași criterii vecunice expuse mai sus, au desființat principiul calculării integrale a sumei divizorilor, preferând să plece de la mult mai micile, mai rapid tratabilele, deja pre-calculatele numărător și numitor abundențial pentru fondul 1 (și pentru fondul 2 aveam din 2019). Programele de tip spirală, prin definiția lor, aveau mult mai multe, exponențial mai multe elemente de legătură de luat în calcul (la 100 de elemente de înmulțire-împărțire, pentru spirală ieșeau 100*100 de combinații posibile, și puteam să mă concentrez pe fondul 1 în loc să mă mai uit atâta la fondul 2 și să le amestec).

Pentru acest lucru, cu nr și nm în locul sumelor, am putut să mai reduc din codul-sursă folosit în varianta de dinainte a programelor pentru numere, având mai puține cazuri de abordare numerică decât la sume, însă am contra-compensat prin numărul mare de programe, în special de tip MODNUM, imde ajunsesem să fac chiar și varianta în care același program trebuia să trateze factorii de legătură pari cu pari, pari cu impari, impari cu pari și impari cu impari (adică la înmulțire și respectiv la împărțire).

Mai târziu, în orice caz după luna iulie 2021, am mai redus din numărul de programe MODNUM, păstrând separată modalitatea de adresare către fișierele cu factori de legătură înmulțire-împărțire, ca VC/VCMPZ și COEFLEG să fie încărcate la alegere, prin pasare de parametru în linia de comandă a programelor, de către programele de MODNUM. Cele cu factori din COEFLEG au silaba LEG în denumire. Cred că reducerea a constat în eliminarea unor programe de tip MODNUM care făceau același lucru ca altele sau erau nenecesare. Încerc să-mi amintesc, oricum ajunsesem cel puțin la concluzia că o parte din MODNUM-uri nu sunt necesare, dar nu reușesc să îmi dau seama care erau. Am crezut la început că am unificat citirea fișierelor de legătură COEFLEG/VEC, dar văd că sursele pentru ele au rămas separate. Mă gândesc că totuși chiar despre asta era vorba - că se puteau păstra fișierele fără LEG și unifica funcțiile de citire, ce însă prin codul de TOLIL.h iar văd că nu s-a făcut. Era făcubil.

Însă descoperirea asta, orișicum, s-a întâmplat abia prin anul 2022, la o altă rundă de numere, nu în vara lui 2021.

Mă mai uitam oricum, cu regularitate, pe site-urile numericana.com și http://wwwhomes.uni-bielefeld.de/achim/mpn.html, după noile numere hemiperfecte și multiperfecte, și am mai avut și de acolo de luat elemente + să le adaug noile numere prime și numerele derivate de fond 1, care să se încadreze în definiția fondului 1. Dar în 2021 am tot rămas la cota 30009 - a fost o noapte frumoasă atunci și dătătoare de speranțe, joi, 13 mai din 2021, iar după aceea... nimic nou pe front la fondul 1!

Comentarii

Postări populare