factmsieve.py 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267
  1. #!/usr/bin/python
  2. # factmsieve.py - A Python driver for GGNFS and MSIEVE
  3. #
  4. # Copyright (c) 2010, Brian Gladman
  5. #
  6. # All rights reserved.
  7. #
  8. # Redistribution and use in source and binary forms, with
  9. # or without modification, are permitted provided that the
  10. # following conditions are met:
  11. #
  12. # Redistributions of source code must retain the above
  13. # copyright notice, this list of conditions and the
  14. # following disclaimer.
  15. #
  16. # Redistributions in binary form must reproduce the
  17. # above copyright notice, this list of conditions and
  18. # the following disclaimer in the documentation and/or
  19. # other materials provided with the distribution.
  20. #
  21. # The names of its contributors may not be used to
  22. # endorse or promote products derived from this
  23. # software without specific prior written permission.
  24. #
  25. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  26. # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
  27. # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  28. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  29. # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  30. # THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  31. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33. # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  34. # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  36. # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  37. # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  38. # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  39. # POSSIBILITY OF SUCH DAMAGE.
  40. # This code is a conversion of the script factmsieve.pl
  41. # which is Copyright 2004, Chris Monico. His contribution
  42. # is acknowledged, as are those of all who contributed to
  43. # the original Perl script.
  44. #
  45. # I also acknowledge the invaluable help I have had from
  46. # Jeff Gilchrist in testing amd debugging this driver.
  47. # Without his support during its development, it would
  48. # never have reached a working state.
  49. #
  50. # The support of Wingware, who kindly donated their first
  51. # class Python development environment, is acknowledged.
  52. # Minor adjustments by Daniel Suteu (2019) to make it work
  53. # on Arch Linux with the `ggnfs-svn` AUR package installed.
  54. # Experimental porting to Python 3 by Daniel Suteu (2020).
  55. from __future__ import print_function
  56. from __future__ import division
  57. import os, sys, random, re, functools, string, socket, signal
  58. import time, subprocess, gzip, glob, math, tempfile, datetime
  59. import atexit, threading, collections, multiprocessing, platform
  60. VERSION = '0.86'
  61. # Set binary directory paths
  62. GGNFS_PATH = '/usr/bin'
  63. MSIEVE_PATH = '/usr/bin'
  64. # Set the number of CPU cores and threads
  65. NUM_CORES = 1
  66. THREADS_PER_CORE = 1
  67. USE_CUDA = False
  68. GPU_NUM = 0
  69. MSIEVE_POLY_TIME_LIMIT = 0
  70. MIN_NFS_BITS = 264
  71. # msieve polynomial search leading coefficients limits
  72. # search from POLY_MIN_LC + 1 to POLY_MAX_LC inclusive
  73. POLY_MIN_LC = 0
  74. POLY_MAX_LC = 4000
  75. # Set global flags to control operation
  76. CHECK_BINARIES = True
  77. CHECK_POLY = True
  78. CLEANUP = False
  79. DOCLASSICAL = False
  80. NO_DEF_NM_PARAM = False
  81. PROMPTS = False
  82. SAVEPAIRS = True
  83. USE_KLEINJUNG_FRANKE_PS = False
  84. USE_MSIEVE_POLY = True
  85. VERBOSE = True
  86. # End of configuration options
  87. # number of msieve poly search threads to launch
  88. MS_THREADS = NUM_CORES * THREADS_PER_CORE
  89. # number of siever threads to launch
  90. SV_THREADS = NUM_CORES * THREADS_PER_CORE
  91. # number of linear algebra threads to launch
  92. LA_THREADS = NUM_CORES * THREADS_PER_CORE
  93. # ggnfs and msieve executable flie names
  94. MSIEVE = 'msieve'
  95. MAKEFB = 'makefb'
  96. PROCRELS = 'procrels'
  97. POL51M0 = 'pol51m0b'
  98. POL51OPT = 'pol51opt'
  99. POLYSELECT = 'polyselect'
  100. PLOT = 'autogplot.sh'
  101. # default parameter files
  102. DEFAULT_PAR_FILE = 'def-par.txt'
  103. DEFAULT_POLSEL_PAR_FILE = 'def-nm-params.txt'
  104. # temporary files
  105. PARAMFILE = '.params'
  106. RELSBIN = 'rels.bin'
  107. if sys.platform.startswith('win'):
  108. EXE_SUFFIX = '.exe'
  109. else:
  110. EXE_SUFFIX = ''
  111. NICE_PATH = ''
  112. # static global variables
  113. PNUM = 0
  114. LARGEP = 3
  115. LARGEPRIMES = '-' + str(LARGEP) + 'p'
  116. nonPrefDegAdjust = 12
  117. polySelTimeMultiplier = 1.0
  118. # poly5 parameters
  119. pol5_p = { 'max_pst_time':0, 'search_a5step':0, 'npr':0, 'normmax':0.0,
  120. 'normmax1':0.0, 'normmax2':0.0, 'murphymax':0.0 }
  121. # poly select parameters
  122. pols_p = { 'degree':0, 'maxs1':0, 'maxskew':0, 'goodscore':0.0,
  123. 'examinefrac':0.0, 'j0':0, 'j1':0, 'estepsize':0, 'maxtime':0 }
  124. # lattice sieve parameters
  125. lats_p = { 'rlim':0, 'alim':0, 'lpbr':0, 'lpba':0, 'mfbr':0, 'mfba':0,
  126. 'rlambda':0.0, 'alambda':0.0, 'qintsize':0, 'lss':1,
  127. 'siever': 'gnfs-lasieve4I10e', 'minrels':0, 'currels':0 }
  128. # classical sieve parameters
  129. clas_p = { 'a0':0, 'a1':0, 'b0':0, 'b1':0, 'cl_a':0, 'cl_b':0 }
  130. # polynomial parameters
  131. poly_p = { 'n':0, 'degree':0, 'm':0, 'skew':0.0, 'coeff':dict() }
  132. # factorisation parameters
  133. fact_p = { 'n':0, 'dec_digits':0, 'type':'', 'knowndiv':0, 'snfs_difficulty':0,
  134. 'digs':0, 'qstart':0, 'qstep':0, 'q0':0, 'dd':0, 'primes':list(),
  135. 'comps':list(), 'divisors':list(),
  136. 'q_dq':collections.deque([(0,0,0)] * SV_THREADS) }
  137. # Utillity Routines
  138. # print an error message and exit
  139. def die(x, rv = -1):
  140. print(x)
  141. sys.exit(rv)
  142. def sig_exit(x, y):
  143. die('Signal caught. Terminating...')
  144. # obtain a float or an int from a string
  145. def get_nbr(s):
  146. try:
  147. return float(s)
  148. except ValueError:
  149. try:
  150. return int(s)
  151. except ValueError:
  152. pass
  153. return None
  154. # delete a file (unlink equivalent)
  155. def delete_file(fn):
  156. if os.path.exists(fn):
  157. try:
  158. os.unlink(fn)
  159. except WindowsError:
  160. pass
  161. # GREP on a list of text lines
  162. def grep_l(pat, lines):
  163. r = []
  164. c = re.compile(pat)
  165. for l in lines:
  166. if c.search(l):
  167. r += [re.sub('\r|\n', ' ', l)]
  168. return r
  169. # GREP on a named file
  170. def grep_f(pat, file_path):
  171. r = []
  172. c = re.compile(pat)
  173. try:
  174. with open(file_path, 'r') as in_file:
  175. for l in in_file:
  176. if c.search(l):
  177. r += [re.sub('\r|\n', ' ', l)]
  178. return r
  179. except IOError:
  180. die("can't find file " + file_path)
  181. # concatenate file 'app' to file 'to'
  182. def cat_f(app, to):
  183. try:
  184. with open(to, 'ab') as out_file:
  185. try:
  186. with open(app, 'rb') as in_file:
  187. if VERBOSE:
  188. print('appending {0:s} to {1:s}'.format(app, to))
  189. buf = in_file.read(8192)
  190. while buf:
  191. out_file.write(buf)
  192. buf = in_file.read(8192)
  193. except IOError:
  194. die("can't find file " + app)
  195. except IOError:
  196. die("can't find file " + to)
  197. # compress file 'fr' to file 'to'
  198. def gzip_f(fr, to):
  199. try:
  200. with open(fr, 'rb') as in_file:
  201. if VERBOSE:
  202. print('compressing {0:s} to {1:s}'.format(fr, to))
  203. out_file = gzip.open(to, 'ab')
  204. out_file.writelines(in_file)
  205. out_file.close()
  206. except IOError:
  207. die("can't find file " + fr)
  208. # remove comment lines
  209. def chomp_comment(s):
  210. return re.sub('#.*', '', s).strip()
  211. # produce date/time string for log
  212. def date_time_string() :
  213. dt = datetime.datetime.today()
  214. return dt.strftime('%a %b %d %H:%M:%S %Y ')
  215. # write string to log(s):
  216. def write_string_to_log(s):
  217. with open(CWD + LOGNAME, 'a') as out_f:
  218. print(date_time_string() + s, file = out_f)
  219. def output(s, console = True, log = True):
  220. if console:
  221. print(s)
  222. if log:
  223. write_string_to_log(s)
  224. # find processor speed
  225. def proc_speed():
  226. if os.sys.platform.startswith('win'):
  227. if sys.version_info[0] == 2:
  228. from _winreg import OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE
  229. else:
  230. from winreg import OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE
  231. h = OpenKey(HKEY_LOCAL_MACHINE,
  232. 'HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0')
  233. mhz = float(QueryValueEx(h, '~MHz')[0])
  234. else:
  235. tmp = grep_f('cpu MHz\s+:\s+', '/proc/cpuinfo')
  236. m = re.search('\s*cpu MHz\s+:\s+([0-9]+)', tmp[0])
  237. mhz = float(m.group(1)) if m else 0.0
  238. return 1e-3 * mhz
  239. # check that an executable file exists
  240. def check_binary(exe):
  241. if CHECK_BINARIES:
  242. pth = MSIEVE_PATH if exe == MSIEVE else GGNFS_PATH
  243. pth = os.path.join(pth, exe + EXE_SUFFIX)
  244. if not os.path.exists(pth):
  245. print('-> Could not find the program: {0:s}.'.format(exe))
  246. print('-> Did you set the paths properly in this script?')
  247. print('-> They are currently set to:')
  248. print('-> GGNFS_BIN_PATH = {0:s}'.format(GGNFS_PATH))
  249. print('-> MSIEVE_BIN_PATH = {0:s}'.format(MSIEVE_PATH))
  250. sys.exit(-1)
  251. # run an executable file
  252. def run_exe(exe, args, inp = '', in_file = None, out_file = None,
  253. log = True, display = VERBOSE, wait = True):
  254. al = {} if VERBOSE else {'creationflags' : 0x08000000 }
  255. if sys.platform.startswith('win'):
  256. # priority_high = 0x00000080
  257. # priority_normal = 0x00000020
  258. # priority_idle = 0x00000040
  259. al['creationflags'] = al.get('creationflags', 0) | 0x00000040
  260. #else:
  261. #al['preexec_fn'] = NICE_PATH
  262. if in_file and os.path.exists(in_file):
  263. al['stdin'] = open(in_file, 'r')
  264. if out_file:
  265. if out_file == subprocess.PIPE:
  266. md = '> PIPE'
  267. al['stdout'] = subprocess.PIPE
  268. elif os.path.exists(out_file):
  269. md = '>> ' + out_file
  270. al['stdout'] = open(out_file, 'a')
  271. else:
  272. md = '> ' + out_file
  273. al['stdout'] = open(out_file, 'w')
  274. cs = '-> {0:s} {1:s}'.format(exe, args)
  275. if in_file:
  276. cs += '< {0:s}'.format(in_file)
  277. if out_file:
  278. cs += md
  279. output(cs, console = display, log = log)
  280. ex = os.path.join((GGNFS_PATH if exe != MSIEVE
  281. else MSIEVE_PATH), exe + EXE_SUFFIX)
  282. p = subprocess.Popen([ex] + args.split(' '), **al)
  283. if not wait:
  284. return p
  285. if out_file == subprocess.PIPE:
  286. if sys.version_info[0] == 3:
  287. res = p.communicate(input=inp.encode())[0].decode()
  288. else:
  289. res = p.communicate(input=inp)[0]
  290. if res:
  291. res = re.split('(?:\r|\n)*', res)
  292. ret = p.poll()
  293. return (ret, res)
  294. else:
  295. return p.wait()
  296. def run_msieve(ap, extn='', parallel=False):
  297. rel = os.path.abspath(CWD)
  298. dp = os.path.join(rel, DATNAME + extn)
  299. lp = os.path.join(rel, LOGNAME + extn)
  300. ip = os.path.join(rel, ININAME + extn)
  301. fp = os.path.join(rel, FBNAME + extn)
  302. args = ('-s {0:s} -l {1:s} -i {2:s} -nf {3:s} '
  303. .format(dp, lp, ip, fp))
  304. if parallel:
  305. op = os.path.join(rel, OUTNAME + extn)
  306. ret = run_exe(MSIEVE, args + ap, out_file=op, wait=False)
  307. else:
  308. ret = run_exe(MSIEVE, args + ap)
  309. os.chdir(CWD)
  310. return ret
  311. # generate a list of primes
  312. def prime_list(n):
  313. sieve = [False, False] + [True] * (n - 1)
  314. for i in range(2, int(n ** 0.5) + 1):
  315. if sieve[i]:
  316. m = n // i - i
  317. sieve[i * i : n + 1 : i] = [False] * (m + 1)
  318. return [i for i in range(n + 1) if sieve[i]]
  319. # greatest common divisor
  320. def gcd(x, y):
  321. if x == 0:
  322. return y
  323. elif y == 0:
  324. return x
  325. else:
  326. return gcd(y % x, x)
  327. # Miller Rabin 'probable prime' test
  328. #
  329. # returns 'False' if 'n' is definitely composite
  330. # returns 'True' if 'n' is prime or probably prime
  331. #
  332. # 'r' is the number of trials performed
  333. def miller_rabin(n, r = 10):
  334. t = n - 1
  335. s = 0
  336. while not t & 1:
  337. t >>= 1
  338. s += 1
  339. for i in range(r):
  340. a = random.randint(2, n - 1)
  341. x = pow(a, t, n)
  342. if x != 1 and x != n - 1:
  343. for j in range(s - 1):
  344. x = (x * x) % n
  345. if x == 1:
  346. return False
  347. if x == n - 1:
  348. break
  349. else:
  350. return False
  351. return True
  352. # determine if n is probably prime - return
  353. # 0 if n is 0, 1 or composite
  354. # 1 if n is probably prime
  355. # 2 if n is definitely prime
  356. def probable_prime_p(nn, r):
  357. n = abs(nn)
  358. if n <= 2:
  359. return 2 if n == 2 else 0
  360. # trial division
  361. for p in prime_list(1000):
  362. if not n % p:
  363. return 2 if n == p else 0
  364. if p * p > n:
  365. return 2
  366. # Fermat test
  367. if pow(random.randint(2, n - 1), n - 1, n) != 1:
  368. return 0
  369. # Miller-Rabin test
  370. return 1 if miller_rabin(n, r) else 0
  371. # count the number of lines in a file
  372. def linecount(file_path):
  373. count = 0
  374. if not os.path.exists(file_path):
  375. die('can\'t open {0:s}'.format(file_path))
  376. with open(file_path, 'r') as in_file:
  377. for l in in_file:
  378. count += 1
  379. return count
  380. # Read the log file to see if we've found all the prime
  381. # divisors of N yet.
  382. def get_primes(fact_p):
  383. with open(LOGNAME, 'r') as in_f:
  384. for l in in_f:
  385. m1 = re.search('r\d+=(\d+)\s+', l.rstrip())
  386. if m1:
  387. val = int(m1.group(1))
  388. if len(val) > 1 and len(val) < len(fact_p['ndivfree']):
  389. # Is this a prime divisor or composite?
  390. m2 = re.search('\(pp(\d+)\)', l)
  391. if m2:
  392. # If this is a prime we don't already have, add it.
  393. found = False
  394. for p in fact_p['primes']:
  395. if val == p:
  396. found = True
  397. if not found:
  398. fact_p['primes'].append(val)
  399. else:
  400. fact_p['comps'].append(val)
  401. # Now, try to figure out if we have all the prime factors:
  402. x = itertools.reduce(lambda x,y : x * y, fact_p['primes'], 1)
  403. if x == fact_p['ndivfree'] or probab_prime_p(fact_p['ndivfree'] // x, 10):
  404. if x != fact_p['ndivfree']:
  405. fact_p['primes'].append(fact_p['ndivfree'] // x)
  406. for p in fact_p['primes']:
  407. cs = '-> p: {0:s} (pp{1:d})'.format(val, len(val))
  408. output(cs)
  409. return True
  410. # Here, we could try to recover other factors by division,
  411. # but until we have a primality test available, this would
  412. # be pointless since we couldn't really know if we're done.
  413. return False
  414. # The parameter degree, if nonzero, will let this function adjust
  415. # parameters for SNFS factorizations with a predetermined polynomial
  416. # of degree that is not the optimal degree.
  417. nonPrefDegAdjust = 12
  418. def load_default_parameters(nfs_type, digits, degree,
  419. fact_p, pols_p, lats_p, clas_p):
  420. if nfs_type == 'gnfs':
  421. lats_p['lss'] = 0
  422. pth = "/usr/share/ggnfs-svn/def-par.txt"
  423. if not os.path.exists(pth):
  424. die('Could not find default parameter file {0:s}!'
  425. .format(pth))
  426. with open(pth, 'r') as in_f:
  427. par_digits = 0
  428. par_degree = 0
  429. how_close = 1000
  430. for l in in_f:
  431. l = chomp_comment(l.strip()).strip()
  432. if l:
  433. tu = l.split(',')
  434. t = tu[0]
  435. if t == nfs_type:
  436. o = 2
  437. cand_digits = int(tu[1])
  438. cand_degree = int(tu[o + 0])
  439. s1 = abs(cand_digits - digits)
  440. s2 = abs(cand_digits - nonPrefDegAdjust - digits) + nonPrefDegAdjust
  441. # try to properly handle crossover from degree 4 to degree 5
  442. if (s1 if nfs_type == 'gnfs' or not degree or degree == cand_degree
  443. or par_degree == cand_degree - 1 else s2) < how_close:
  444. how_close = (s2 if nfs_type != 'gnfs' and degree
  445. and cand_degree != degree else s1)
  446. par_digits = cand_digits
  447. par_degree = cand_degree
  448. pols_p['maxs1'] = int(tu[o + 1])
  449. pols_p['maxskew'] = int(tu[o + 2])
  450. pols_p['goodscore'] = float(tu[o + 3])
  451. pols_p['examinefrac'] = float(tu[o + 4])
  452. pols_p['j0'] = int(tu[o + 5])
  453. pols_p['j1'] = int(tu[o + 6])
  454. pols_p['estepsize'] = int(tu[o + 7])
  455. pols_p['maxtime'] = int(tu[o + 8])
  456. lats_p['rlim'] = int(tu[o + 9])
  457. lats_p['alim'] = int(tu[o + 10])
  458. lats_p['lpbr'] = int(tu[o + 11])
  459. lats_p['lpba'] = int(tu[o + 12])
  460. lats_p['mfbr'] = int(tu[o + 13])
  461. lats_p['mfba'] = int(tu[o + 14])
  462. lats_p['rlambda'] = float(tu[o + 15])
  463. lats_p['alambda'] = float(tu[o + 16])
  464. lats_p['qintsize'] = int(tu[o + 17])
  465. clas_p['cl_a'] = int(tu[o + 18])
  466. clas_p['cl_b'] = int(tu[o + 19])
  467. fact_p['qstep'] = lats_p['qintsize']
  468. fact_p['digs'] = digits / 0.72 if nfs_type == 'gnfs' else digits
  469. # 0.72 is inspired by T.Womack's crossover 28/29 for GNFS-144 among other consideration
  470. if fact_p['digs'] >= 160:
  471. # the table parameters are easily splined; the table may be not needed at all --SB.
  472. lats_p['rlim'] = lats_p['alim'] = int(0.07 * 10 ** (fact_p['digs'] / 60.0) + 0.5) * 100000
  473. lats_p['lpbr'] = lats_p['lpba'] = int(21 + fact_p['digs'] / 25.0)
  474. lats_p['mfbr'] = lats_p['mfba'] = 2 * lats_p['lpbr'] - (1 if fact_p['digs'] < 190 else 0)
  475. lats_p['rlambda'] = lats_p['alambda'] = 2.5 if fact_p['digs'] < 200 else 2.6
  476. lats_p['qintsize'] = fact_p['qstep'] = 100000
  477. clas_p['cl_a'] = 4000000
  478. clas_p['cl_b'] = 400
  479. par_digits = digits
  480. pols_p['degree'] = par_degree
  481. print('-> Selected default factorization parameters for {0:d} digit level.'.
  482. format(par_digits))
  483. if nfs_type == 'gnfs':
  484. r = (95, 110, 140, 158, 185, 999)
  485. else:
  486. if degree and par_degree != degree:
  487. digits += nonPrefDegAdjust
  488. r = (120, 150, 195, 240, 275, 999)
  489. i = 1
  490. for v in r:
  491. if digits < v:
  492. break
  493. i += 1
  494. else:
  495. die('You are joking?')
  496. lats_p['siever'] = 'gnfs-lasieve4I1' + str(i) + 'e'
  497. output('-> Selected lattice siever: {0:s}'.format(lats_p['siever']))
  498. # These are default parameters for polynomial selection using the
  499. # Kleinjung/Franke tool.
  500. # arg0 = number of digits in N.
  501. def load_pol5_parameters(digits, pol5_p):
  502. par_digits = 0
  503. if NO_DEF_NM_PARAM or digits < 100:
  504. pol5_p['search_a5step'] = 1
  505. pol5_p['npr'] = int(digits / 13.0 - 4.5)
  506. pol5_p['npr'] = pol5_p['npr'] if pol5_p['npr'] > 4 else 4
  507. pol5_p['normmax'] = 10 ** (0.163 * digits - 1.4794)
  508. pol5_p['normmax1'] = 10 ** (0.1522 * digits - 1.6969)
  509. pol5_p['normmax2'] = 10 ** (0.142 * digits - 2.6429)
  510. pol5_p['murphymax'] = 10 ** (-0.0569 * digits - 2.8452)
  511. pol5_p['max_pst_time'] = int(0.000004 / pol5_p['murphymax'])
  512. output('-> Selected polsel parameters for {0:d} digit level.'.format(digits))
  513. return
  514. pth = "/usr/share/ggnfs-svn/def-nm-params.txt"
  515. if not os.path.exists(pth):
  516. die('Could not find default parameter file {0:s}!'
  517. .format(pth))
  518. with open(pth, 'r') as in_f:
  519. how_close = 1000
  520. for l in in_f:
  521. l = chomp_comment(l.strip()).strip()
  522. if l:
  523. tu = l.split(',')
  524. d = int(tu[0])
  525. if abs(d - digits) < how_close:
  526. o = 1
  527. how_close = abs(d - digits)
  528. par_digits = d
  529. pol5_p['max_pst_time'] = 60 * int(tu[o + 0])
  530. pol5_p['search_a5step'] = int(tu[o + 1])
  531. pol5_p['npr'] = int(tu[o + 2])
  532. pol5_p['normmax'] = float(tu[o + 3])
  533. pol5_p['normmax1'] = float(tu[o + 4])
  534. pol5_p['normmax2'] = float(tu[o + 5])
  535. pol5_p['murphymax'] = float(tu[o + 6])
  536. output('-> Selected default polsel parameters for {0:d} digit level.'
  537. .format(par_digits))
  538. # The dictionary entries in this routine map each coefficient as a string
  539. # to the coefficient value as floating point values. The (name, value)
  540. # pairs on the BEGIN_POLY line are also entered into the dictionary for
  541. # each polynomial
  542. pname = ''
  543. def terminate_pol5(x, y):
  544. die('Terminated on {0:s} by SIGINT'.format(pname))
  545. def run_pol5(fact_p, pol5_p, lats_p, clas_p):
  546. global pname
  547. check_binary(POL51M0)
  548. check_binary(POL51OPT)
  549. projectname = NAME + '.polsel'
  550. host = socket.gethostname()
  551. pname = projectname + host + '.' + str(os.getpid())
  552. with open(pname + '.data', 'w') as out_f:
  553. print('N ' + str(fact_p['n']), file = out_f)
  554. pol5_term_flag = False
  555. old_handler = signal.signal(signal.SIGINT, terminate_pol5)
  556. load_pol5_parameters(fact_p['dec_digits'], pol5_p)
  557. pol5_p['max_pst_time'] *= polySelTimeMultiplier
  558. hmult = 1e3
  559. load_default_parameters('gnfs', fact_p['dec_digits'], 5,
  560. fact_p, pols_p, lats_p, clas_p)
  561. bestpolyinf = dict()
  562. bestpolyinf['Murphy_E'] = 0
  563. start_time = time.time()
  564. nerr = 0
  565. h_lo = 0
  566. while not pol5_term_flag and nerr < 2:
  567. h_hi = h_lo + pol5_p['search_a5step']
  568. output('-> Searching leading coefficients from {0:g} to {1:g}'
  569. .format(h_lo * hmult + 1, h_hi * hmult))
  570. args = ('-b {0:s} -v -v -p {1:d} -n {2:g} -a {3:g} -A {4:g}'
  571. .format(pname, pol5_p['npr'], pol5_p['normmax'], h_lo, h_hi))
  572. if not run_exe(POL51M0, args, out_file = pname + '.log'):
  573. # lambda-comp related errors can be skipped and some polys are
  574. # then found ull5-comp related are probably fatal, but let the
  575. # elapsed time.time() take care of them
  576. nerr = 0
  577. suc = grep_f('success', pname + '.log')
  578. changed = False
  579. if suc:
  580. args = ('-b {0:s} -v -v -n {1:g} -N {2:g} -e {3:g}'
  581. .format(pname, pol5_p['normmax1'], pol5_p['normmax2'], pol5_p['murphymax']))
  582. ret = run_exe(POL51OPT, args, out_file = pname + '.log')
  583. if ret:
  584. die('Abnormal return value {0:d}. Terminating...'.format(ret))
  585. cat_f(pname + '.51.m', projectname + '.51.m.all')
  586. with open(pname + '.cand', 'r') as in_f:
  587. polyinf = dict()
  588. for l in in_f:
  589. l = l.rstrip()
  590. if re.match('BEGIN POLY', l):
  591. l = re.sub('BEGIN POLY', '', l)
  592. l = re.sub('^ #', '', l)
  593. tu = l.split()
  594. for i in range(0, len(tu), 2):
  595. polyinf[tu[i]] = float(tu[i + 1])
  596. elif re.match('END POLY', l):
  597. if polyinf['Murphy_E'] > bestpolyinf['Murphy_E']:
  598. bestpolyinf = polyinf.copy()
  599. changed = True
  600. polyinf = dict()
  601. else:
  602. tu = l.split()
  603. polyinf[re.sub('^X', 'c', tu[0])] = int(tu[1])
  604. if changed:
  605. for key in sorted(bestpolyinf):
  606. print(key, ':', bestpolyinf[key])
  607. with open(NAME + '.poly', 'w') as out_f:
  608. print('name: {0:s}'.format(NAME), file = out_f)
  609. print('n: {0:d}'.format(fact_p['n']), file = out_f)
  610. for key in reversed(sorted(bestpolyinf)):
  611. if re.match('c\d+', key) or re.match('Y\d+', key):
  612. print('{0:s}: {1:d}'
  613. .format(key, bestpolyinf[key]), file = out_f)
  614. elif re.match('skewness', key):
  615. print('skew: {0:<10.2f}'
  616. .format(bestpolyinf[key]), file = out_f)
  617. elif key == 'M':
  618. print(key, bestpolyinf[key])
  619. print('# {0:s} {1:d}'
  620. .format(key, bestpolyinf[key]), file = out_f)
  621. else:
  622. print('# {0:s} {1:g}'
  623. .format(key, bestpolyinf[key]), file = out_f)
  624. print('type: {0:s}'.format('gnfs'), file = out_f)
  625. print('rlim: {0:d}'.format(lats_p['rlim']), file = out_f)
  626. print('alim: {0:d}'.format(lats_p['alim']), file = out_f)
  627. print('lpbr: {0:d}'.format(lats_p['lpbr']), file = out_f)
  628. print('lpba: {0:d}'.format(lats_p['lpba']), file = out_f)
  629. print('mfbr: {0:d}'.format(lats_p['mfbr']), file = out_f)
  630. print('mfba: {0:d}'.format(lats_p['mfba']), file = out_f)
  631. print('rlambda: {0:g}'.format(lats_p['rlambda']), file = out_f)
  632. print('alambda: {0:g}'.format(lats_p['alambda']), file = out_f)
  633. print('qintsize: {0:d}'.format(lats_p['qintsize']), file = out_f)
  634. cat_f(pname +'.cand', projectname + '.cand.all')
  635. delete_file(pname + '.cand')
  636. print('-> =====================================================')
  637. output('-> Best score so far: {0:g} (good_score={1:g})'
  638. .format(bestpolyinf['Murphy_E'], pol5_p['murphymax']))
  639. print('-> =====================================================')
  640. delete_file(pname + '.log')
  641. delete_file(pname + '.51.m')
  642. if time.time() > start_time + pol5_p['max_pst_time']:
  643. pol5_term_flag = True
  644. h_lo = h_hi
  645. delete_file(pname + '.data')
  646. signal.signal(signal.SIGINT, old_handler)
  647. # We will start with a higher leading coefficient divisor. When it
  648. # appears that we are searching in an interesting range, it will
  649. # be backed down so that the resulting range can be searched with
  650. # a finer resolution. This means that from time to time, the same
  651. # poly will be found several times as we hone in on a region.
  652. def run_poly_select(fact_p, pols_p, lats_p, clas_p):
  653. check_binary(POLYSELECT)
  654. lcd_choices = (2, 4, 4, 12, 12, 24, 24, 48, 48, 144, 144, 720, 5040)
  655. lcd_level = 4 + (fact_p['dec_digits'] - 70) // 10
  656. if lcd_level < 0:
  657. lcd_level = 0
  658. if lcd_level > 12:
  659. lcd_level = 12
  660. output('-> Starting search with leading coefficient divisor {0:d}'
  661. .format(lcd_choices[lcd_level]))
  662. load_default_parameters('gnfs', fact_p['dec_digits'], 0,
  663. fact_p, pols_p, lats_p, clas_p)
  664. pols_p['maxtime'] *= polySelTimeMultiplier
  665. best_score = 0.0
  666. start_time = time.time()
  667. done = False
  668. best_lc = 1
  669. last_lc = 0
  670. multiplier = 0.75
  671. e_lo = 1
  672. while not done:
  673. e_hi = e_lo + pols_p['estepsize']
  674. lcd = lcd_choices[lcd_level]
  675. with open(NAME + '.polsel', 'w') as out_f:
  676. print('name: {0:s}'.format(NAME), file = out_f)
  677. print('n: {0:d}'.format(fact_p['n']), file = out_f)
  678. print('deg: {0:d}'.format(pols_p['degree']), file = out_f)
  679. print('bf: {0:s}.best.poly'.format(NAME), file = out_f)
  680. print('maxs1: {0:d}'.format(pols_p['maxs1']), file = out_f)
  681. print('maxskew: {0:d}'.format(pols_p['maxskew']), file = out_f)
  682. print('enum: {0:d}'.format(lcd), file = out_f)
  683. print('e0: {0:d}'.format(e_lo), file = out_f)
  684. print('e1: {0:d}'.format(e_hi), file = out_f)
  685. print('cutoff: {0:g}'.format(0.75 * pols_p['goodscore']), file = out_f)
  686. print('examinefrac: {0:g}'.format(pols_p['examinefrac']), file = out_f)
  687. print('j0: {0:d}'.format(pols_p['j0']), file = out_f)
  688. print('j1: {0:d}'.format(pols_p['j1']), file = out_f)
  689. args = '-if {0:s}.polsel'.format(NAME)
  690. ret = run_exe(POLYSELECT, args)
  691. if ret:
  692. die('Return value res. Terminating...'.format(ret))
  693. # Find the score of the best polynomial: E(F1,F2) =
  694. inp = True
  695. try:
  696. tmp = grep_f('E\(F1,F2\) =', NAME + '.best.poly')
  697. except IOError:
  698. inp = False
  699. if inp:
  700. score = tmp[0]
  701. score = float(re.sub('.*E\(F1,F2\) =', '', tmp[0]))
  702. tmp = grep_f('^c' + str(pols_p['degree']), NAME + '.best.poly')
  703. m = re.search('^c' + str(pols_p['degree']) + ':\s([\+\-]*\d*)', tmp[0])
  704. lc = int(m.group(1))
  705. else:
  706. score = 0.0
  707. if (score > multiplier * pols_p['goodscore'] and lc != best_lc
  708. and lc != last_lc ):
  709. multipler = 1.1 * multiplier if multiplier < 0.9 / 1.1 else multiplier
  710. last_lc = lc
  711. new_lcd_level = lcd_level - 1 if lcd > 0 else 0
  712. e_lo = e_lo * lcd_choices[lcd_level] // lcd_choices[new_lcd_level] - pols_p['estepsize']
  713. if lcd_level != new_lcd_level:
  714. print('-> Leading coefficient divisor dropped from {0:d} to {1:d}.'
  715. .format(lcd_choices[lcd_level], lcd_choices[new_lcd_level]))
  716. lcd_level = new_lcd_level
  717. if score > best_score and lc != best_lc:
  718. best_score = score
  719. best_lc = lc
  720. last_best_time = time.time()
  721. os.rename(NAME + '.best.poly', NAME + '.thebest.poly')
  722. # We should now fill in the missing parameters with the default
  723. # loaded in from table. Do this now, so that the user has the
  724. # option to kill the script and still have a viable poly file.
  725. with open(NAME + '.thebest.poly', 'r') as in_f:
  726. with open(NAME + '.poly', 'w') as out_f:
  727. for l in in_f:
  728. l = l.rstrip()
  729. if l.find('rlim:') != -1:
  730. l = 'rlim: {0:d}'.format(lats_p['rlim'])
  731. elif l.find('alim:') != -1:
  732. l = 'alim: {0:d}'.format(lats_p['alim'])
  733. elif l.find('lpbr:') != -1:
  734. l = 'lpbr: {0:d}'.format(lats_p['lpbr'])
  735. elif l.find('lpba:') != -1:
  736. l = 'lpba: {0:d}'.format(lats_p['lpba'])
  737. elif l.find('mfbr:') != -1:
  738. l = 'mfbr: {0:d}'.format(lats_p['mfbr'])
  739. elif l.find('mfba:') != -1:
  740. l = 'mfba: {0:d}'.format(lats_p['mfba'])
  741. elif l.find('rlambda:') != -1:
  742. l = 'rlambda: {0:g}'.format(lats_p['rlambda'])
  743. elif l.find('alambda:') != -1:
  744. l = 'alambda: {0:g}'.format(lats_p['alambda'])
  745. elif l.find('qintsize:') != -1:
  746. l = 'qintsize: {0:d}'.format(lats_p['qintsize'])
  747. if l:
  748. print(l, file = out_f)
  749. print('type: gnfs', file = out_f)
  750. delete_file(NAME + '.thebest.poly')
  751. delete_file(NAME + '.best.poly')
  752. print('-> =====================================================')
  753. output('-> Best score so far: {0:g} (good_score={1:g}) '
  754. .format(best_score, pols_p['goodscore']))
  755. print('-> =====================================================')
  756. # We will allow another 5 minutes just in case there happens to
  757. # be a really good poly nearby (or the 'good_score' value was too low)
  758. if best_score > 1.4 * pols_p['goodscore']:
  759. done = (time.time() > last_best_time + 300)
  760. done |= (time.time() > start_time + pols_p['maxtime'])
  761. e_lo = e_hi
  762. output('-> Using poly with score={0:f}'.format(best_score))
  763. delete_file(NAME + '.polsel')
  764. def msieve_mpqs(fact_p):
  765. with open(ININAME, 'w') as out_f:
  766. out_f.write('{0:d}'.format(fact_p['n']))
  767. ret = run_msieve('-v')
  768. if ret:
  769. die('Msieve Error: return value {0:d}... terminating...'.format(ret))
  770. return True
  771. procs = []
  772. def terminate_threads(sig=signal.SIGINT, frame=None):
  773. global procs
  774. try:
  775. for p in procs:
  776. if p.poll() == None:
  777. p.terminate()
  778. for p in procs:
  779. if p.poll() == None:
  780. p.wait()
  781. except:
  782. pass
  783. def fb_to_poly():
  784. with open(NAME + '.poly', 'w') as out_f:
  785. with open(NAME + '.fb', 'r') as in_f:
  786. for l in in_f:
  787. m = re.match('N\s+(\d+)', l)
  788. if m:
  789. print('n: {0:s}'.format(m.group(1)), file = out_f)
  790. m = re.match('SKEW\s+(\d*\.\d*)', l)
  791. if m:
  792. skew = float(m.group(1))
  793. m = re.match('R(\d+)\s+([+-]?\d+)', l)
  794. if m:
  795. print('Y{0:s}: {1:s}'.format(m.group(1),
  796. m.group(2)), file = out_f)
  797. m = re.match('A(\d+)\s+([+-]?\d+)', l)
  798. if m:
  799. print('c{0:s}: {1:s}'.format(m.group(1),
  800. m.group(2)), file = out_f)
  801. try:
  802. print('skew: {0:<10.2f}'.format(skew), file = out_f)
  803. print('type: gnfs', file = out_f)
  804. except:
  805. die('{0:s}.fb is not in the correct format'.format(NAME))
  806. def find_best(fn, bestscore, poly):
  807. try:
  808. in_f = open(fn, 'r')
  809. except IOError:
  810. die("can't read " + fn)
  811. # first input line (followed by polynomial lines) format:
  812. # norm 1.498232e-10 alpha -5.818790 e 9.344e-10 rroots 3
  813. # 1 2 3 4 5 6 7 8
  814. for l in in_f:
  815. word = l.split()
  816. if word[1] == 'norm':
  817. better = False
  818. if float(word[6]) > bestscore:
  819. bestscore = float(word[6])
  820. output("Best score so far: {0:s}".format(l.strip()))
  821. better = True
  822. poly = []
  823. if better:
  824. poly += [l]
  825. in_f.close()
  826. return (bestscore, poly)
  827. def run_msieve_poly(fact_p, minv, maxv):
  828. global procs
  829. poly = []
  830. bestscore = 0
  831. if USE_CUDA or MS_THREADS == 1:
  832. with open(ININAME, 'w') as out_f:
  833. out_f.write('{0:d}'.format(fact_p['n']))
  834. if USE_CUDA:
  835. ap = '-g {0:d} -v -np'.format(GPU_NUM)
  836. bp = ' Is CUDA enabled?'
  837. else:
  838. ap = '-v -np'
  839. bp = ''
  840. if MSIEVE_POLY_TIME_LIMIT:
  841. ap = '-d {0:d} '.format(MSIEVE_POLY_TIME_LIMIT) + ap
  842. else:
  843. ap += ' {0:d},{1:d} -t {2:d}'.format(minv if minv else 1, maxv, NUM_CORES)
  844. ret = run_msieve(ap)
  845. if ret:
  846. die('Msieve Error: return value {0:d}.{1:s} Terminating...'.format(ret, bp))
  847. bestscore, poly = find_best(NAME + '.msieve.dat.p', bestscore, poly)
  848. else:
  849. old_handler = signal.signal(signal.SIGINT, terminate_threads)
  850. for j in range(MS_THREADS):
  851. extn = '.T' + str(j)
  852. with open(ININAME + extn, 'w') as out_f:
  853. out_f.write('{0:d}'.format(fact_p['n']))
  854. procs = [None] * MS_THREADS
  855. ret = 0
  856. base = minv
  857. if os.path.exists(NAME + '.lcf'):
  858. try:
  859. with open(NAME + '.lcf', 'r') as in_f:
  860. t = int(in_f.readline().strip())
  861. if minv < t < maxv:
  862. base = t
  863. elif t >= maxv:
  864. die("previous run conflict (delete {0:s}.lcf to run again)".format(NAME))
  865. except IOError:
  866. die("Can't read " + NAME + '.lcf')
  867. term = False
  868. while base < maxv and not ret:
  869. for j in range(MS_THREADS):
  870. extn = '.T' + str(j)
  871. retc = 0 if not procs[j] else procs[j].poll()
  872. if retc != None:
  873. ret |= retc
  874. if os.path.exists(NAME + '.lcf'):
  875. try:
  876. with open(NAME + '.lcf', 'r') as in_f:
  877. base = int(in_f.readline().strip())
  878. except IOError:
  879. die("Can't read " + NAME + '.lcf')
  880. try:
  881. with open(NAME + '.lcf', 'w') as out_f:
  882. print(base + 100, file=out_f)
  883. except IOError:
  884. die("Can't write to " + NAME + '.lcf')
  885. procs[j] = run_msieve('-np {0:d},{1:d} -v '.format(base + 1, base + 100), extn, parallel=True)
  886. base += 100
  887. try:
  888. time.sleep(1)
  889. except:
  890. term = True
  891. break
  892. if ret:
  893. #print('an error occurred during polynomial search')
  894. #return run_msieve_poly(fact_p, minv * 2, maxv * 2)
  895. die('an error occurred during polynomial search')
  896. if term:
  897. terminate_threads()
  898. die('msieve terminated')
  899. for j in range(MS_THREADS):
  900. nm = NAME + '.fb.T' + str(j)
  901. if os.path.exists(nm):
  902. delete_file(nm)
  903. output('deleted ' + nm)
  904. nm = NAME + '.dat.T' + str(j) + '.p'
  905. bestscore, poly = find_best(NAME + '.dat.T' + str(j) + '.p', bestscore, poly)
  906. if bestscore == 0:
  907. output('could not find any polynomials')
  908. die('could not find any polynomials')
  909. with open(NAME + '.poly', 'w') as out_f:
  910. with open(NAME + '.n', 'r') as in_f:
  911. for l in in_f:
  912. out_f.writelines([l])
  913. out_f.writelines(poly + ['type: gnfs'])
  914. out_f.close()
  915. return True
  916. def change_parameters(lats_p):
  917. check_binary(MAKEFB)
  918. check_binary(PROCRELS)
  919. cs = ('-> Parameter change detected, dumping relations... ')
  920. output(cs)
  921. args = '-fb {0:s}.fb -prel {1:s} -dump'.format(NAME, RELSBIN)
  922. ret = run_exe(PROCRELS, args)
  923. if ret:
  924. die('Return value {0:d}. Terminating...'.format(ret))
  925. for f in glob.iglob(RELSBIN + '*'):
  926. delete_file(f)
  927. for f in glob.iglob('cols*'):
  928. delete_file(f)
  929. for f in glob.iglob('deps*'):
  930. delete_file(f)
  931. delete_file('factor.easy')
  932. for f in glob.iglob('lpindex*'):
  933. delete_file(f)
  934. for f in glob.iglob(NAME + '.*.afb.*'):
  935. delete_file(f)
  936. output('-> Making new factor base files...')
  937. args = ('-rl {0[rlim]:d} -al {0[alim]:d} -lpbr {0[lpbr]:d} -lpba {0[lpba]:d}'
  938. '{1:s} -of {2:s}.fb -if {2:s}.poly'.format(lats_p, LARGEPRIMES, NAME))
  939. ret = run_exe(MAKEFB, args)
  940. if ret:
  941. die('Return value {0:d}. Terminating...'.format(ret))
  942. output('-> Reprocessing siever output...')
  943. i = 0
  944. while os.path.exists('spairs.dump.i'):
  945. args = (' -fb {0:s}.fb -prel {1:s} -newrel spairs.dump.i -nolpcount'
  946. .format(NAME, RELSBIN))
  947. ret = run_exe(PROCRELS, args)
  948. i = i + 1
  949. # Update the paramfile, used by this script to detect change
  950. # in parameter settings.
  951. with open(PARAMFILE, 'w') as out_f:
  952. print('rlim: {0:d}'.format(lats_p['rlim']), file = out_f)
  953. print('alim: {0:d}'.format(lats_p['alim']), file = out_f)
  954. print('lbpr: {0:s}'.format(LBPR), file = out_f)
  955. print('lbpa: {0:s}'.format(LBPA), file = out_f)
  956. def check_for_parameter_change(lats_p):
  957. if not os.path.exists(PARAMFILE):
  958. output('-> Creating param file to detect parameter changes...')
  959. with open(PARAMFILE, 'w') as out_f:
  960. print('rlim: {0:d}'.format(lats_p['rlim']), file = out_f)
  961. print('alim: {0:d}'.format(lats_p['alim']), file = out_f)
  962. print('lpbr: {0:d}'.format(lats_p['lpbr']), file = out_f)
  963. print('lpba: {0:d}'.format(lats_p['lpba']), file = out_f)
  964. return
  965. # Okay - it exists. We should check it to see if the
  966. # parameters are the same as the current ones.
  967. with open(PARAMFILE, 'r') as in_f:
  968. old_params = in_f.readlines()
  969. tmp = grep_l('rlim:', old_params)
  970. old_rlim = int(re.sub('.*rlim:', '', tmp[0]))
  971. tmp = grep_l('alim:', old_params)
  972. old_alim = int(re.sub('.*alim:', '', tmp[0]))
  973. tmp = grep_l('lpbr:', old_params)
  974. old_lpbr = int(re.sub('.*lpbr:', '', tmp[0]))
  975. tmp = grep_l('lpba:', old_params)
  976. old_lpba = int(re.sub('.*lpba:', '', tmp[0]))
  977. if (old_rlim != lats_p['rlim'] or old_alim != lats_p['alim'] or
  978. old_lpbr != lats_p['lpbr'] or old_lpba != lats_p['lpba']):
  979. change_parameters(lats_p)
  980. else:
  981. output('-> No parameter change detected, resuming... ')
  982. def plot_lp():
  983. if CHECK_BINARIES:
  984. if not os.path.exists(PLOT):
  985. return
  986. if not os.path.exists(LOGNAME):
  987. return
  988. with open(LOGNAME, 'r') as in_f:
  989. with open('.lprels', 'w') as out_f:
  990. print('0, 0', file = out_f)
  991. with open('.rels', 'w') as out_rels:
  992. print('0, 0', file = out_rels)
  993. for l in in_f:
  994. l = l.rstrip().upper()
  995. m = re.search('LARGEPRIMES')
  996. if m:
  997. l = re.sub('\[.*]\s*','', l) # strip date
  998. l = re.sub('(LARGEPRIMES: |RELATIONS: )', '', l) # strip the labels
  999. tu = l.strip().split(',')
  1000. print('{0:s}, {1:d}'.format(tu[1], int(tu[0]) - int(tu[1])), FILE = outf)
  1001. m = re.search('FINALFF')
  1002. if m:
  1003. l = re.sub('\[.*]\s*','', l) # strip date
  1004. l = re.sub('(LARGEPRIMES: |RELATIONS: )', '', l) # strip the labels
  1005. tu = l.strip().split(',')
  1006. print('{0:s}, {1:s}'.format(tu[0], tu[1]), file = out_rels)
  1007. os.putenv('XAXIS', 'Total relations')
  1008. os.putenv('YAXIS', '')
  1009. args = 'xprimes.png \'ExcessLargePrimes\' .lprels'
  1010. ret = run_exe(PLOT, args)
  1011. if ret:
  1012. die('Return value {0:d}. Terminating...'.format(ret))
  1013. os.putenv('XAXIS', 'Total relations')
  1014. os.putenv('YAXIS', 'Full relation-sets')
  1015. args = 'relations.png \'TotalFF\' .rels'
  1016. ret = run_exe(PLOT, args)
  1017. if ret:
  1018. die('Return value {0:d}. Terminating...'.format(ret))
  1019. delete_file('.lprels')
  1020. delete_file('.rels')
  1021. class is_missing(Exception):
  1022. def __init__(self, x):
  1023. self.value = x
  1024. def __str__(self):
  1025. return self.value
  1026. def check_parameters(fact_p, poly_p, lats_p):
  1027. check_binary(MSIEVE)
  1028. check_binary(lats_p['siever'])
  1029. if CHECK_BINARIES:
  1030. delete_file('.lprels')
  1031. delete_file('.rels')
  1032. with open('.rels', 'w') as out_f:
  1033. print('{0:d}'.format(fact_p['n']), file = out_f)
  1034. delete_file('.lprels')
  1035. delete_file('.rels')
  1036. if not fact_p['n']:
  1037. die('Error: \'n\' not supplied!')
  1038. if not (poly_p['m'] or 'Y1' in poly_p['coeff']):
  1039. die('Error: \'m\' not supplied!')
  1040. if not 'c' + str(poly_p['degree']) in poly_p['coeff']:
  1041. die('Error: polynomial not supplied!')
  1042. if not poly_p['skew']:
  1043. poly_p['skew'] = (abs( poly_p['coeff']['c0'] / poly_p['coeff']['c'
  1044. + str(poly_p['degree'])]) ** (1.0 / poly_p['degree']))
  1045. print('-> Using calculated skew {0:<10.2f}'.format(poly_p['skew']))
  1046. try :
  1047. if not lats_p['rlim']: raise is_missing('rlim')
  1048. if not lats_p['alim']: raise is_missing('alim')
  1049. if not lats_p['lpbr']: raise is_missing('lpbr')
  1050. if not lats_p['lpba']: raise is_missing('lpba')
  1051. if not lats_p['mfbr']: raise is_missing('mfbr')
  1052. if not lats_p['mfba']: raise is_missing('mfba')
  1053. if not lats_p['rlambda']: raise is_missing('rlambda')
  1054. if not lats_p['alambda']: raise is_missing('alambda')
  1055. if not fact_p['qstep']: raise is_missing('qstep')
  1056. except is_missing as x:
  1057. die('Error: \'' + str(x) + '\' not supplied!')
  1058. def get_parm_int(data, match):
  1059. tmp = grep_l('^' + match + ':', data)
  1060. if tmp:
  1061. m = re.search('^' + match + ':\s*(-?\d+)', tmp[0])
  1062. if m:
  1063. return int(m.group(1))
  1064. return None
  1065. # Read default parameters first. Then we will just override
  1066. # by any user-supplied parameters.
  1067. def read_parameters(fact_p, poly_p, lats_p):
  1068. with open(NAME + '.poly', 'r') as in_f:
  1069. file_lines = in_f.readlines()
  1070. fact_p['n'] = get_parm_int(file_lines, 'n')
  1071. fact_p['dec_digits'] = len(str(fact_p['n']))
  1072. # Find the polynomial degree.
  1073. coefvals = dict()
  1074. coeff_lines = grep_l('^c\d+:', file_lines)
  1075. d = 0
  1076. for l in coeff_lines:
  1077. # Grab the coefficient index
  1078. # First char of line 'c' followed by a digit string.
  1079. m = re.search('^c(\d+):\s*(-?\d+)', l)
  1080. if m:
  1081. key = int(m.group(1))
  1082. val = int(m.group(2))
  1083. if key > d:
  1084. d = key
  1085. if key in coefvals:
  1086. print('-> Warning: redefining c{0:d}'.format(key))
  1087. coefvals[key] = val
  1088. poly_p['degree'] = get_parm_int(file_lines, 'deg')
  1089. if not poly_p['degree']:
  1090. poly_p['degree'] = d
  1091. if poly_p['degree'] != d:
  1092. print('-> Error: poly file specifies degree {0:d} but highest poly'
  1093. .format(poly_p['degree']))
  1094. print('-> coefficient given is c{0:d}!'.format(d))
  1095. sys.exit(-1)
  1096. for i in range(d):
  1097. if i not in coefvals:
  1098. coefvals[i] = 0
  1099. commonfac = 0
  1100. first = True
  1101. for key in reversed(sorted(coefvals)):
  1102. if first:
  1103. commonfac = coefvals[key]
  1104. first = False
  1105. else:
  1106. commonfac = gcd(commonfac, coefvals[key])
  1107. if CHECK_POLY and commonfac > 1:
  1108. print('-> Error: poly coefficients have a common factor commonfac.'
  1109. ' Please divide it out.')
  1110. sys.exit(-1)
  1111. denom = get_parm_int(file_lines, 'Y1')
  1112. numer = get_parm_int(file_lines, 'Y0')
  1113. poly_p['m'] = get_parm_int(file_lines, 'm')
  1114. if denom and numer:
  1115. if denom < 0:
  1116. denom = -denom
  1117. else:
  1118. numer = -numer
  1119. # print '-> Common root is numer / denom\n'
  1120. # paranoia if CHECK_POLY is set
  1121. if CHECK_POLY:
  1122. cf = gcd(numer, denom)
  1123. if cf != 1:
  1124. print('-> Error: {0:d} and {1:d} have a common factor {2:d}.'
  1125. ' Please divide it out.'.format(denom, numer, cf))
  1126. sys.exit()
  1127. if CHECK_POLY and poly_p['m'] and (denom * poly_p['m'] - numer) % fact_p['n']:
  1128. print('-> Error: {0:d} * {1:d} + {2:d} != 0 mod {0:d}!'
  1129. .format(denom, poly_p['m'], numer, fact_p['n']))
  1130. sys.exit(-1)
  1131. polyval = 0
  1132. if denom and numer:
  1133. for i in range(poly_p['degree'] + 1):
  1134. polyval += coefvals[i] * numer ** i * denom ** (poly_p['degree'] - i)
  1135. elif poly_p['m']:
  1136. # print('-> Common root is {0:d}'.format(poly_p['m']))
  1137. for i in range(poly_p['degree'], -1, -1):
  1138. polyval = poly_p['m'] * polyval + coefvals[i]
  1139. if CHECK_POLY and polyval == 0:
  1140. print('-> Warning: evaluated polynomial value polyval is negative or zero.')
  1141. print('-> This is at least a little strange.')
  1142. if CHECK_POLY and polyval % fact_p['n'] != 0:
  1143. print('-> Error: evaluated polynomial value polyval is not a multiple of n!')
  1144. sys.exit(-1)
  1145. # print '-> Evaluated value is polyval\n'
  1146. tmp = grep_l('type:', file_lines)
  1147. m = re.search('.*type:\s+(gnfs|snfs)', tmp[0])
  1148. if not m:
  1149. print('-> Error: poly file should contain one of the following lines:')
  1150. print('-> type: snfs')
  1151. print('-> type: gnfs')
  1152. print('-> Please add the appropriate line and re-run.')
  1153. sys.exit(-1)
  1154. elif m.group(1) == 'gnfs':
  1155. fact_p['type'] = 'gnfs'
  1156. load_default_parameters('gnfs', fact_p['dec_digits'], poly_p['degree'],
  1157. fact_p, pols_p, lats_p, clas_p)
  1158. else:
  1159. fact_p['type'] = 'snfs'
  1160. # We need the difficulty level of the number, which may be
  1161. # noticably larger than the number of digits.
  1162. fact_p['snfs_difficulty'] = len(str(polyval)) # + math.log(int(str(polyval)[0:1])) - 1
  1163. print('-> SNFS_DIFFICULTY is about {0:d}.'.format(fact_p['snfs_difficulty']))
  1164. load_default_parameters('snfs', fact_p['snfs_difficulty'], poly_p['degree'],
  1165. fact_p, pols_p, lats_p, clas_p)
  1166. # Now look for user-supplied parameters.
  1167. fact_p['q0'] = 0
  1168. with open(NAME + '.poly', 'r') as in_f:
  1169. for l in in_f:
  1170. l = l.rstrip()
  1171. l = chomp_comment(l)
  1172. l = l.strip()
  1173. if len(l) and l.find(':') != - 1:
  1174. token, val = l.split(':')
  1175. if len(token) > 0 and len(val) > 0:
  1176. if token == 'n':
  1177. fact_p['n'] = int(val)
  1178. elif token == 'm':
  1179. poly_p['m'] = int(val)
  1180. elif token == 'rlim':
  1181. lats_p['rlim'] = int(val)
  1182. elif token == 'alim':
  1183. lats_p['alim'] = int(val)
  1184. elif token == 'lpbr':
  1185. lats_p['lpbr'] = int(val)
  1186. elif token == 'lpba':
  1187. lats_p['lpba'] = int(val)
  1188. elif token == 'mfbr':
  1189. lats_p['mfbr'] = int(val)
  1190. elif token == 'mfba':
  1191. lats_p['mfba'] = int(val)
  1192. elif token == 'rlambda':
  1193. lats_p['rlambda'] = float(val)
  1194. elif token == 'alambda':
  1195. lats_p['alambda'] = float(val)
  1196. elif token == 'knowndiv':
  1197. fact_p['knowndiv'] = int(val)
  1198. elif token == 'skew':
  1199. poly_p['skew'] = float(val)
  1200. elif token == 'q0':
  1201. fact_p['q0'] = int(val)
  1202. elif token == 'qintsize':
  1203. lats_p['qintsize'] = int(val)
  1204. elif token == 'lss':
  1205. lats_p['lss'] = int(val)
  1206. else:
  1207. m = re.search('(c|Y).', token)
  1208. if m :
  1209. poly_p['coeff'][token] = int(val)
  1210. fact_p['qstep'] = lats_p['qintsize']
  1211. if fact_p['knowndiv']:
  1212. if fact_p['n'] % fact_p['knowndiv']:
  1213. die('-> Error: knowndiv {0:d} does not divide {0:d}!'
  1214. .format(fact_p['knowndiv'], fact_p['n']))
  1215. fact_p['ndivfree'] = fact_p['n'] // fact_p['knowndiv']
  1216. fact_p['n'] = fact_p['ndivfree']
  1217. else:
  1218. fact_p['ndivfree'] = fact_p['n']
  1219. if probable_prime_p(fact_p['ndivfree'], 10):
  1220. die('-> Error: {0:d} is probably prime!'.format(fact_p['n']))
  1221. if fact_p['q0'] == 0:
  1222. fact_p['q0'] = (lats_p['rlim'] if lats_p['lss'] else lats_p['alim']) // 2
  1223. fact_p['qstart'] = fact_p['q0']
  1224. check_for_parameter_change(lats_p)
  1225. # sieving intervals are triples (q_start, q_pos, q_end) that
  1226. # are kept in a Python deque list in fact_p['q_dq']. In each
  1227. # sieving step, the q interval (q0 .. q0 + qstep) is divided
  1228. # into sub-intervals for sieving by the available threads on
  1229. # this machine. When this step is completed, the intervals
  1230. # are updated for the next step.
  1231. # When termainated by a user interrupt the siever will write
  1232. # a file named 'LASTSPQ<N>', with <N> = 100 * PNUM + TNUM if
  1233. # multi-threaded or PNUM if single threaded (thread number =
  1234. # TNUM, processor number = PNUM). This gives the q position
  1235. # when the siever was stopped. These files from each thread
  1236. # are used to create a file, JOBNAME.resume, that is used to
  1237. # restart the sieving. It has the fileds:
  1238. #
  1239. # Q0: the Q0 value when terminated
  1240. # QSTEP: the QSTEP value when terminated
  1241. # QQ<N>: the sieving interval (ql, qp, qh)
  1242. # for thread<N> when it was stopped
  1243. # The following three routines manipulate sieve intervals
  1244. # and are collected together here to assist in further
  1245. # improvements. The algorithms are primitive right now.
  1246. def init_q_dq(fact_p, n_threads, qbase):
  1247. inc = int(fact_p['qstep'] // n_threads)
  1248. for j in range(n_threads):
  1249. if j >= len(fact_p['q_dq']):
  1250. fact_p['q_dq'].append(0)
  1251. if not fact_p['q_dq'][j]:
  1252. fact_p['q_dq'][j] = ((qbase, qbase, qbase + inc))
  1253. qbase += inc
  1254. def update_q_dq(fact_p, n_threads, n_clients):
  1255. for j in range(n_threads):
  1256. ql, qp, qh = fact_p['q_dq'].popleft()
  1257. ql += n_clients * fact_p['qstep']
  1258. qh += n_clients * fact_p['qstep']
  1259. fact_p['q_dq'].append((ql, ql, qh))
  1260. def divide_q_dq(fact_p, n_threads):
  1261. while len(fact_p['q_dq']) < n_threads:
  1262. ql, qp, qh = fact_p['q_dq'].popleft()
  1263. t = int((qh - qp) // 2)
  1264. fact_p['q_dq'].append((ql, qp, qp + t))
  1265. fact_p['q_dq'].append((ql, qp + t, qh))
  1266. def write_resume_file(n_threads, fact_p):
  1267. with open(JOBNAME + '.resume', 'w') as out_f:
  1268. if 'q0' in fact_p:
  1269. print('Q0: {0:d}'.format(fact_p['q0']), file = out_f)
  1270. if 'qstep' in fact_p:
  1271. print('QSTEP: {0:d}'.format(fact_p['qstep']), file = out_f)
  1272. for j in range(n_threads):
  1273. ql, qp, qh = fact_p['q_dq'][j]
  1274. print('QQ{0:d}: {1:d}, {2:d}, {3:d}'
  1275. .format(j, ql, qp, qh), file = out_f)
  1276. def read_resume_file():
  1277. rn = JOBNAME + '.resume'
  1278. fact_p['q_dq'].clear()
  1279. with open(rn, 'r') as in_f:
  1280. tmp = in_f.readlines()
  1281. for l in tmp:
  1282. m = re.search('Q0:\s+(\d+)', l)
  1283. if m:
  1284. q0 = int(m.group(1))
  1285. m = re.search('QSTEP:\s+(\d+)', l)
  1286. if m:
  1287. qstep = int(m.group(1))
  1288. m = re.search('QQ(\d+):\s*(\d+),\s*(\d+),\s*(\d+)', l)
  1289. if m:
  1290. while int(m.group(1)) >= len(fact_p['q_dq']):
  1291. fact_p['q_dq'].append(0)
  1292. fact_p['q_dq'][int(m.group(1))] = (int(m.group(2)),
  1293. int(m.group(3)), int(m.group(4)))
  1294. return (q0, qstep)
  1295. def setup(fact_p, poly_p, lats_p, client, n_clients, n_threads):
  1296. # Should we resume from an earlier run? #
  1297. resume = os.path.exists(JOBNAME + '.resume')
  1298. if resume:
  1299. if PROMPTS:
  1300. ip = ('-> It appears that an earlier attempt was interrupted. Resume? (y/n) ')
  1301. while True:
  1302. if sys.version_info[0] < 3:
  1303. r = raw_input(ip)
  1304. else:
  1305. r = input(ip)
  1306. if r == 'y' or r == 'Y':
  1307. resume = True
  1308. break
  1309. elif r == 'n' or r == 'N':
  1310. resume = False
  1311. break
  1312. if fact_p['type'] == 'gnfs':
  1313. if lats_p['lpbr'] == 25:
  1314. lats_p['minrels'] = int(38000.0 * (fact_p['dec_digits'] - 47))
  1315. elif lats_p['lpbr'] == 26:
  1316. lats_p['minrels'] = int(91000.0 * (fact_p['dec_digits'] - 55))
  1317. elif lats_p['lpbr'] == 27:
  1318. lats_p['minrels'] = int(150000.0 * (fact_p['dec_digits'] - 61))
  1319. elif lats_p['lpbr'] == 28:
  1320. lats_p['minrels'] = int(440000.0 * (fact_p['dec_digits'] - 89))
  1321. else:
  1322. lats_p['minrels'] = int(10.0 ** (fact_p['dec_digits'] / 41.0 + 4.0))
  1323. else:
  1324. lats_p['minrels'] = int(10.0 ** (fact_p['digs'] / 70.0 + 4.6))
  1325. # lats_p['minrels'] = int(0.2 * 1.442695 *((2 ** lats_p['lpba']) /lats_p['lpba'] + (2 ** lats_p['lpbr']) / lats_p['lpbr']))
  1326. output('-> Estimated minimum relations needed: {0:g}'.format(1.0 * lats_p['minrels']))
  1327. # Setup the parameters for sieving ranges. #
  1328. if not resume:
  1329. if client_id == 1:
  1330. if os.path.exists(NAME + '.n') and not os.path.exists(NAME + '.poly'):
  1331. delete_file(LOGNAME)
  1332. output('-> cleaning up before a restart')
  1333. # Clean up any junk leftover from an earlier attempt.
  1334. for f in glob.iglob('cols*'):
  1335. delete_file(f)
  1336. for f in glob.iglob('deps*'):
  1337. delete_file(f)
  1338. delete_file('factor.easy')
  1339. for f in glob.iglob('lpindex*'):
  1340. delete_file(f)
  1341. for f in glob.iglob(RELSBIN + '*'):
  1342. delete_file(f)
  1343. delete_file('spairs.out')
  1344. delete_file('spairs.out.gz')
  1345. delete_file(NAME + '.fb')
  1346. for f in glob.iglob('*.afb.0'):
  1347. delete_file(f)
  1348. for f in glob.iglob('*.afb.1'):
  1349. delete_file(f)
  1350. delete_file('.params')
  1351. # Was a discriminant divisor supplied?
  1352. if fact_p['dd']:
  1353. with open(LOGNAME, 'a') as out_f:
  1354. print('{0:d}'.format(fact_p['dd']), file = out_f)
  1355. # Create msieve file
  1356. with open(ININAME, 'w') as out_f:
  1357. print('{0:d}'.format(fact_p['n']), file = out_f)
  1358. with open(DATNAME, 'w') as out_f:
  1359. print('N {0:d}'.format(fact_p['n']), file = out_f)
  1360. with open(FBNAME, 'w') as out_f:
  1361. print('N {0:d}'.format(fact_p['n']), file = out_f)
  1362. print('SKEW {0:<10.2f}'.format(poly_p['skew']), file = out_f)
  1363. if not 'Y1' in poly_p['coeff']:
  1364. poly_p['coeff']['Y1'] = 1
  1365. poly_p['coeff']['Y0'] = -poly_p['m']
  1366. for key in reversed(sorted(poly_p['coeff'])):
  1367. if key[0] == 'c':
  1368. print('A{0:d} {1:d}'.format(int(key[1:]), poly_p['coeff'][key]), file = out_f)
  1369. print('R1 {0:d}'.format(poly_p['coeff']['Y1']), file = out_f)
  1370. print('R0 {0:d}'.format(poly_p['coeff']['Y0']), file = out_f)
  1371. print('FAMAX {0:d}'.format(lats_p['alim']), file = out_f)
  1372. print('FRMAX {0:d}'.format(lats_p['rlim']), file = out_f)
  1373. print('SALPMAX {0:d}'.format(2 ** lats_p['lpba']), file = out_f)
  1374. print('SRLPMAX {0:d}'.format(2 ** lats_p['lpbr']), file = out_f)
  1375. fact_p['q0'] = fact_p['qstart']
  1376. fact_p['q_dq'].clear()
  1377. else:
  1378. fact_p['q0'] = 0
  1379. try:
  1380. t = read_resume_file()
  1381. fact_p['q0'], fact_p['qstep'] = t
  1382. output('-> resuming a block for q from {0:d} to {1:d}'
  1383. .format(fact_p['q0'], fact_p['q0'] + fact_p['qstep']))
  1384. except IOError:
  1385. print('-> Could not determine a starting q value!')
  1386. print('-> Please enter a starting point for the special q: ')
  1387. if sys.version_info[0] < 3:
  1388. tmp = raw_input()
  1389. else:
  1390. tmp = input()
  1391. fact_p['q0'] = int(tmp)
  1392. if not fact_p['q0']:
  1393. fact_p['q0'] = fact_p['qstart']
  1394. fact_p['q_dq'].clear()
  1395. # add sieve intervals if the sieve interval queue is not long enough
  1396. if 0 < len(fact_p['q_dq']) < n_threads:
  1397. divide_q_dq(fact_p, n_threads)
  1398. else:
  1399. t_q = int(fact_p['q0'] + ((client - 1) % n_clients) * fact_p['qstep'])
  1400. init_q_dq(fact_p, n_threads, t_q)
  1401. def job_out0(sieve_lim, lats_p, out_f):
  1402. print('rlim: {0:d}'.format(sieve_lim[1]), file = out_f)
  1403. print('alim: {0:d}'.format(sieve_lim[0]), file = out_f)
  1404. print('lpbr: {0:d}'.format(lats_p['lpbr']), file = out_f)
  1405. print('lpba: {0:d}'.format(lats_p['lpba']), file = out_f)
  1406. print('mfbr: {0:d}'.format(lats_p['mfbr']), file = out_f)
  1407. print('mfba: {0:d}'.format(lats_p['mfba']), file = out_f)
  1408. print('rlambda: {0:g}'.format(lats_p['rlambda']), file = out_f)
  1409. print('alambda: {0:g}'.format(lats_p['alambda']), file = out_f)
  1410. def job_out1(q0, q1, out_f):
  1411. print('q0: {0:d}'.format(q0), file = out_f)
  1412. print('qintsize: {0:d}'.format(q1 - q0), file = out_f)
  1413. print('#q1:{0:d}'.format(q1), file = out_f)
  1414. def job_out2(clas_p, out_f):
  1415. print('a0: {0:s}'.format(clas_p['a0']), file = out_f)
  1416. print('a1: {0:s}'.format(clas_p['a1']), file = out_f)
  1417. print('b0: {0:s}'.format(clas_p['b0']), file = out_f)
  1418. print('b1: {0:s}'.format(clas_p['b1']), file = out_f)
  1419. def make_sieve_jobfile(FNAME, fact_p, poly_p, lats_p, clas_p = None):
  1420. q0 = fact_p['q0']
  1421. sieve_type = 1 if q0 > 0 or fact_p['qstep'] > 0 else 0
  1422. sieve_lim = [lats_p['alim'], lats_p['rlim'], None]
  1423. if sieve_type == 1:
  1424. if lats_p['lss'] and lats_p['rlim'] > q0:
  1425. sieve_lim[1] = q0 - 1
  1426. sieve_lim[2] = '.afb.1'
  1427. elif not lats_p['lss'] and lats_p['alim'] > q0:
  1428. sieve_lim[0] = q0 - 1
  1429. sieve_lim[2] = '.afb.0'
  1430. for j in range(SV_THREADS):
  1431. ql, qp, qh = fact_p['q_dq'][j]
  1432. t_fname = FNAME + '.T' + str(j)
  1433. delete_file(t_fname)
  1434. output('-> making sieve job for q = {1:d} in {0:d} .. {2:d} as file {3:s}'
  1435. .format(ql, qp, qh, t_fname))
  1436. with open(t_fname, 'w') as out_f:
  1437. print('n: {0:d}'.format(fact_p['n']), file = out_f)
  1438. if poly_p['m']:
  1439. print('m: {0:d}'.format(poly_p['m']), file = out_f)
  1440. # The polynomial coefficients:
  1441. for key in reversed(sorted(poly_p['coeff'])) :
  1442. print('{0:s} {1:d}'.format(key + ':', poly_p['coeff'][key]), file = out_f)
  1443. print('skew: {0:<10.2f}'.format(poly_p['skew']), file = out_f)
  1444. job_out0(sieve_lim, lats_p, out_f)
  1445. if sieve_type == 1:
  1446. job_out1(qp, qh, out_f)
  1447. else:
  1448. job_out2(clas_p, out_f)
  1449. if sieve_lim[2]:
  1450. delete_file(t_fname + sieve_lim[2])
  1451. return sieve_lim[2]
  1452. # arg0 = A value, to sieve [-A,A]
  1453. # arg1 = B0
  1454. # arg2 = B1, to sieve for b values in [B0, B1].
  1455. def run_classical_sieve(a, b0, b1):
  1456. if not DOCLASSICAL:
  1457. return
  1458. max_b = 0
  1459. lastline = 0
  1460. # First, scan the line file and find the largest b-value that was sieved.
  1461. line_file = DATNAME + '.line'
  1462. if os.path.exists(line_file):
  1463. with open(line_file, 'r') as in_f:
  1464. tmp = in_f.readline()
  1465. tmp = in_f.readline()
  1466. bb = int(tmp)
  1467. max_b = bb if bb > max_b else max_b
  1468. max_b = b0 if max_b < b0 else max_b
  1469. if max_b < b1:
  1470. with open(FBNAME, 'a') as out_f:
  1471. print('SLINE {0:d}'.format(a), file = out_f)
  1472. print('-> Line file scanned: resuming classical sieve from b = {0:d}.'
  1473. .format(max_b))
  1474. ret = run_msieve('-t {0:d} -ns {1:d},{2:d}'.format(LA_THREADS, max_b, b1))
  1475. if ret:
  1476. die('Interrupted. Terminating...')
  1477. def log_sieve_time(val):
  1478. write_string_to_log('LatSieveTime: {0:g}'.format(val))
  1479. def read_spq(fact_p):
  1480. for j in range(SV_THREADS):
  1481. ql, qp, qh = fact_p['q_dq'][j]
  1482. try:
  1483. with open('.last_spq' + str(100 * PNUM + j), 'r') as in_f:
  1484. try:
  1485. t = int(in_f.readline().strip())
  1486. except ValueError:
  1487. pass
  1488. else:
  1489. if t > qp:
  1490. fact_p['q_dq'][j] = (ql, t, qh)
  1491. except IOError:
  1492. pass
  1493. def monitor_sieve_threads(procs):
  1494. running, ret = False, 0
  1495. for p in procs:
  1496. retc = p.poll()
  1497. if retc == None:
  1498. running = True
  1499. else:
  1500. ret |= retc
  1501. return (running, ret)
  1502. def run_siever(client_id, n_clients, n_threads, fact_p, lats_p):
  1503. global procs
  1504. old_handler = signal.signal(signal.SIGINT, terminate_threads)
  1505. procs = [None] * SV_THREADS
  1506. siever_option = '-r' if lats_p['lss'] else '-a'
  1507. siever_side = 'rational' if lats_p['lss'] else 'algebraic'
  1508. output('-> entering sieving loop')
  1509. while not os.path.exists(COLSNAME):
  1510. sieve_lim = make_sieve_jobfile(JOBNAME, fact_p, poly_p, lats_p)
  1511. if fact_p['q0'] >= 2 ** lats_p['lpba']:
  1512. print('-> {0:s} : Severe error!'.format(NAME))
  1513. print('-> Current special q = {0:s} has exceeded max. large alg. prime = {1:d)!'
  1514. .format(fact_p['q0'], 2 ** lats_p['lpba']))
  1515. print('-> You can try increasing LPBA, re-launch this script and cross your fingers.')
  1516. print('-> But be aware that if you\'re seeing this, your factorization is taking')
  1517. print('-> much longer than it would have with better parameters.')
  1518. sys.exit(-1)
  1519. write_resume_file(n_threads, fact_p)
  1520. output('-> Lattice sieving {0:s} q from {1:d} to {2:d}.'
  1521. .format(siever_side, fact_p['q0'], fact_p['q0'] + fact_p['qstep']))
  1522. start_time = time.time()
  1523. for j in range(n_threads):
  1524. sn = SIEVER_OUTPUTNAME + '.T' + str(j)
  1525. delete_file(sn)
  1526. args = ('-k -o {0:s} -v -n {1:d} {2:s} {3:s}'
  1527. .format(sn, 100 * PNUM + j, siever_option, JOBNAME + '.T' + str(j)))
  1528. procs[j] = run_exe(lats_p['siever'], args, wait = False)
  1529. ret, running, term = 0, True, False
  1530. while running and not term:
  1531. try:
  1532. time.sleep(1)
  1533. except IOError:
  1534. term = True
  1535. break
  1536. else:
  1537. read_spq(fact_p)
  1538. running, ret = monitor_sieve_threads(procs)
  1539. if ret or term:
  1540. terminate_threads()
  1541. for j in range(n_threads):
  1542. if sieve_lim:
  1543. delete_file(JOBNAME + '.T' + str(j) + sieve_lim)
  1544. cat_f(SIEVER_OUTPUTNAME + '.T' + str(j), SIEVER_OUTPUTNAME)
  1545. delete_file(SIEVER_OUTPUTNAME + '.T' + str(j))
  1546. if ret and ret != -1073741819 or term:
  1547. if isinstance(ret, int):
  1548. output('-> Return value {0:d}. Updating job file and terminating...'
  1549. .format(ret))
  1550. cat_f(SIEVER_OUTPUTNAME, SIEVER_ADDNAME)
  1551. delete_file(SIEVER_OUTPUTNAME)
  1552. write_resume_file(n_threads, fact_p)
  1553. # Record the time to the logfile.
  1554. log_sieve_time(time.time() - start_time)
  1555. die('Terminating...')
  1556. else:
  1557. fact_p['q0'] += n_clients * fact_p['qstep']
  1558. update_q_dq(fact_p, n_threads, n_clients)
  1559. write_resume_file(0, fact_p)
  1560. if not os.path.exists(SIEVER_OUTPUTNAME):
  1561. die('Some error ocurred and no relations were found! Examine the log file.')
  1562. if client_id > 1:
  1563. cat_f(SIEVER_OUTPUTNAME, SIEVER_ADDNAME)
  1564. delete_file(SIEVER_OUTPUTNAME)
  1565. else:
  1566. # Are there relations coming from somewhere else which should be added in?
  1567. if os.path.exists(SIEVER_ADDNAME):
  1568. cat_f(SIEVER_ADDNAME, SIEVER_OUTPUTNAME)
  1569. delete_file(SIEVER_ADDNAME)
  1570. for i in range(n_clients):
  1571. san = 'spairs.add.' + str(i + 1)
  1572. if os.path.exists(san):
  1573. cat_f(san, SIEVER_OUTPUTNAME)
  1574. delete_file(san)
  1575. cat_f(SIEVER_OUTPUTNAME, DATNAME)
  1576. if SAVEPAIRS:
  1577. gzip_f(SIEVER_OUTPUTNAME, 'spairs.save.gz')
  1578. delete_file(SIEVER_OUTPUTNAME)
  1579. if os.path.exists('minrels.txt'):
  1580. with open('minrels.txt', 'r') as in_f:
  1581. tmp = in_f.readline()
  1582. m = re.search('(\d+)', tmp)
  1583. if m:
  1584. lats_p['minrels'] = int(m.group(1))
  1585. lats_p['currels'] = curr_rels = linecount(DATNAME)
  1586. pc = (100.0 * curr_rels) / lats_p['minrels']
  1587. output('Found {0:d} relations, {1:2.1f}% of the estimated minimum ({2:d}).'
  1588. .format(curr_rels, pc, lats_p['minrels']))
  1589. if curr_rels > lats_p['minrels']:
  1590. ret = run_msieve('-t {0:d} -nc1'.format(LA_THREADS))
  1591. if ret:
  1592. die('Return value {0:d}. Terminating...'.format(ret))
  1593. for j in range(n_threads):
  1594. delete_file(JOBNAME + '.T' + str(j))
  1595. log_sieve_time(time.time() - start_time)
  1596. fact_p['last_spq'] = dict()
  1597. delete_file(JOBNAME + '.resume')
  1598. signal.signal(signal.SIGINT, old_handler)
  1599. def summary_name(name, fact_p):
  1600. if fact_p['type'] == 'gnfs':
  1601. s = 'g' + str(fact_p['dec_digits'])
  1602. else :
  1603. s = 's' + str(fact_p['snfs_difficulty'])
  1604. t = os.path.split(name)
  1605. return os.path.join(t[0], s + '-' + t[1] + '.txt')
  1606. poly_time = 0.0
  1607. def output_summary(name, fact_p, pols_p, poly_p, lats_p):
  1608. global poly_time
  1609. # Set the summary file name
  1610. sum_name = summary_name(name, fact_p)
  1611. # Figure the time scale for this machine.
  1612. output('-> Computing time scale for this machine...')
  1613. (ret, res) = run_exe(PROCRELS, '-speedtest', out_file = subprocess.PIPE)
  1614. if res:
  1615. #tmp = grep_l('timeunit:', res) # FIXME
  1616. #timescale = float(re.sub('timeunit:\s*', '', tmp[0])) # FIXME
  1617. timescale = 0.0
  1618. else:
  1619. timescale = 0.0
  1620. # And gather up some stats.
  1621. sieve_time = 0.0
  1622. relproc_time = 0.0
  1623. matrix_time = 0
  1624. sqrt_time = 0
  1625. min_q = max_q = 0
  1626. prunedmat = rels = ''
  1627. rprimes = aprimes = 0
  1628. version = 'Msieve-1.40'
  1629. with open(LOGNAME, 'r') as in_f:
  1630. for l in in_f:
  1631. l = l.rstrip()
  1632. l = re.sub('\s+$', '', l)
  1633. tu = l.split()
  1634. m = re.search('for q from (\d+) to (\d+) as file', l)
  1635. if m:
  1636. t = int(m.group(1))
  1637. min_q = t if t < min_q or not min_q else min_q
  1638. t = int(m.group(2))
  1639. max_q = t if t > max_q or not max_q else max_q
  1640. m = re.search('LatSieveTime:\s*(\d+)', l)
  1641. if m:
  1642. sieve_time += float(m.group(1))
  1643. m = re.search('(Msieve.*)$', l)
  1644. if m:
  1645. version = m.group(1)
  1646. m = re.search('RelProcTime: (\S+)', l)
  1647. if m:
  1648. relproc_time += int(m.group(1))
  1649. m = re.search('BLanczosTime: (\S+)', l)
  1650. if m:
  1651. matrix_time += int(m.group(1))
  1652. m = re.search('sqrtTime: (\S+)', l)
  1653. if m:
  1654. sqrt_time += int(m.group(1))
  1655. m = re.search('rational ideals', l)
  1656. if m:
  1657. rprimes = str(tu[6]) + ' ' + str(tu[7]) + ' ' + str(tu[5])
  1658. m = re.search('algebraic ideals', l)
  1659. if m:
  1660. aprimes = str(tu[6]) + ' ' + str(tu[7]) + ' ' + str(tu[5])
  1661. m = re.search('unique relations', l)
  1662. if m:
  1663. rels = str(tu[-3]) + ' ' + str(tu[-1])
  1664. m = re.search('matrix is', l)
  1665. if m:
  1666. prunedmat = str(tu[7]) + ' x ' + str(tu[9])
  1667. m = re.search('p[0-9]+\s+factor', l)
  1668. if m:
  1669. tmp = int(re.sub('.*factor: ', '', l))
  1670. if 1 < len(str(tmp)) < fact_p['dec_digits']:
  1671. fact_p['divisors'].append(tmp)
  1672. with open('ggnfs.log', 'a') as out_f:
  1673. print('Number: {0:s}'.format(NAME), file = out_f)
  1674. print('N = {0:d}'.format(fact_p['n']), file = out_f)
  1675. for dd in sorted(set(fact_p['divisors'])):
  1676. print('factor: {0:d}'.format(dd), file = out_f)
  1677. # Convert times from seconds to hours.
  1678. poly_time /= 3600.0
  1679. sieve_time /= 3600.0
  1680. relproc_time /= 3600.0
  1681. matrix_time /= 3600.0
  1682. sqrt_time /= 3600.0
  1683. total_time = poly_time + sieve_time + relproc_time + matrix_time + sqrt_time
  1684. with open(sum_name, 'w') as out_f:
  1685. print('Number: {0:s}'.format(NAME), file = out_f)
  1686. print('N = {0:d} ({1:d} digits)'.format(fact_p['n'], fact_p['dec_digits']), file = out_f)
  1687. if fact_p['type'] == 'snfs':
  1688. print('SNFS difficulty: {0:d} digits.'.format(fact_p['snfs_difficulty']), file = out_f)
  1689. print('Divisors found:', file = out_f)
  1690. if fact_p['knowndiv']:
  1691. print(' knowndiv: {0:d}'.format(fact_p['knowndiv']), file = out_f)
  1692. r = 1
  1693. for dd in sorted(set(fact_p['divisors'])):
  1694. print('r{0:d}={1:d} (pp{2:d})'.format(r, dd, len(str(dd))), file = out_f)
  1695. r += 1
  1696. print('Version: {0:s}'.format(version), file = out_f)
  1697. if fact_p['type'] == 'mpqs':
  1698. print('Completed using mpqs mode', file=out_f)
  1699. else:
  1700. print('Total time: {0:1.2f} hours.'.format(total_time), file = out_f)
  1701. print('Scaled time: {0:1.2f} units (timescale= {1:1.3f}).'
  1702. .format(total_time * timescale, timescale))
  1703. try:
  1704. with open(NAME + '.poly', 'r') as in_f:
  1705. print('Factorization parameters were as follows:', file = out_f)
  1706. for l in in_f:
  1707. l = l.rstrip()
  1708. print(l, file = out_f)
  1709. except IOError:
  1710. pass
  1711. siever_side = 'rational' if lats_p['lss'] else 'algebraic'
  1712. print('Factor base limits: {0:d}/{1:d}'.format(lats_p['rlim'], lats_p['alim']), file = out_f)
  1713. print('Large primes per side: {0:d}'.format(LARGEP), file = out_f)
  1714. print('Large prime bits: {0:d}/{1:d}'.format(lats_p['lpbr'], lats_p['lpba']), file = out_f)
  1715. print('Sieved {0:s} special-q in [{1:d}, {2:d})'.format(siever_side, min_q, max_q), file = out_f)
  1716. print('Total raw relations: {0:d}'.format(lats_p['currels']), file = out_f)
  1717. print('Relations: {0:s}'.format(rels), file = out_f)
  1718. print('Pruned matrix : {0:s}'.format(prunedmat), file = out_f)
  1719. if poly_time:
  1720. print('Polynomial selection time: {0:1.2f} hours.'.format(poly_time), file = out_f)
  1721. print('Total sieving time: {0:1.2f} hours.'.format(sieve_time), file = out_f)
  1722. print('Total relation processing time: {0:1.2f} hours.'.format(relproc_time), file = out_f)
  1723. print('Matrix solve time: {0:1.2f} hours.'.format(matrix_time), file = out_f)
  1724. print('time per square root: {0:1.2f} hours.'.format(sqrt_time), file = out_f)
  1725. if fact_p['type'] == 'snfs':
  1726. fact_p['digs'] = fact_p['snfs_difficulty']
  1727. DFL = ('{0[type]:s},{0[digs]:d},{1[degree]:d},{3:d},{4:d},{5:g},{6:g},{7:d},'
  1728. '{8:d},{9:d},{10:d},{2[rlim]:d},{2[alim]:d},{2[lpbr]:d},{2[lpba]:d},'
  1729. '{2[mfbr]:d},{2[mfba]:d},{2[rlambda]:g},{2[alambda]:g},{2[qintsize]:d}'
  1730. .format(fact_p, poly_p, lats_p, 0,0,0,0,0,0,0,0))
  1731. elif fact_p['type'] == 'gnfs':
  1732. fact_p['digs'] = fact_p['dec_digits'] - 1
  1733. DFL = ('{0[type]:s},{0[digs]:d},{1[degree]:d},{2[maxs1]:d},{2[maxskew]:d},'
  1734. '{2[goodscore]:g},{2[examinefrac]:g},{2[j0]:d},{2[j1]:d},{2[estepsize]:d},'
  1735. '{2[maxtime]:d},{3[rlim]:d},{3[alim]:d},{3[lpbr]:d},{3[lpba]:d},'
  1736. '{3[mfbr]:d},{3[mfba]:d},{3[rlambda]:g},{3[alambda]:g},{3[qintsize]:d}'
  1737. .format(fact_p, poly_p, pols_p, lats_p))
  1738. print('Prototype def-par.txt line would be: {0:s}'.format(DFL), file = out_f)
  1739. print('total time: {0:1.2f} hours.'.format(total_time), file = out_f)
  1740. print(platform.processor(), file = out_f)
  1741. print('processors: {0:d}, speed: {1:.2f}GHz'
  1742. .format(multiprocessing.cpu_count(), proc_speed()), file = out_f)
  1743. t = platform.platform()
  1744. if len(t):
  1745. print(platform.platform(), file = out_f)
  1746. t = platform.python_version_tuple()
  1747. print('Running Python {0[0]:s}.{0[1]:s}'.format(t), file = out_f)
  1748. output('-> Factorization summary written to {0:s}'.format(sum_name))
  1749. # ###########################################
  1750. # ########## Begin execution here ###########
  1751. # ###########################################
  1752. print('-> ________________________________________________________________')
  1753. print('-> | Running factmsieve.py, a Python driver for MSIEVE with GGNFS |')
  1754. print('-> | sieving support. It is Copyright, 2010, Brian Gladman and is |')
  1755. print('-> | a conversion of factmsieve.pl that is Copyright, 2004, Chris |')
  1756. print('-> | Monico. Version {0:s} (Python 2.6 or later) 20th June 2011. |'.format(VERSION))
  1757. print('-> |______________________________________________________________|')
  1758. if len(sys.argv) != 2 and len(sys.argv) != 4:
  1759. print('USAGE: {0:s} <number file | poly file | msieve poly file> [ id num]'
  1760. .format(sys.argv[0]))
  1761. print(' where <polynomial file> is a file with the poly info to use')
  1762. print(' or <number file> is a file containing the number to factor.')
  1763. print(' Optional: id/num specifies that this is client <id> of <num>')
  1764. print(' clients total (clients are numbered 1,2,3,...).')
  1765. print(' (Multi-client mode is still very experimental - it should only')
  1766. print(' be used for testing, and is only intended as a hack for running')
  1767. print(' conveniently on a very small number of machines - perhaps 5 - 10).')
  1768. sys.exit(-1)
  1769. GGNFS_PATH = os.path.abspath(GGNFS_PATH)
  1770. MSIEVE_PATH = os.path.abspath(MSIEVE_PATH)
  1771. CWD = os.getcwd() + '/'
  1772. NAME = sys.argv[1]
  1773. NAME = re.sub('\.(poly|fb|n)', '', NAME)
  1774. # NOTE: These names are global
  1775. LOGNAME = NAME + '.log'
  1776. JOBNAME = NAME + '.job'
  1777. ININAME = NAME + '.ini'
  1778. DATNAME = NAME + '.dat'
  1779. FBNAME = NAME + '.fb'
  1780. OUTNAME = NAME + '.msp'
  1781. DEPFNAME = DATNAME + '.dep'
  1782. COLSNAME = DATNAME + '.cyc'
  1783. SIEVER_OUTPUTNAME = 'spairs.out'
  1784. SIEVER_ADDNAME = 'spairs.add'
  1785. signal.signal(signal.SIGINT, sig_exit)
  1786. if len(sys.argv) == 4:
  1787. client_id = int(sys.argv[2])
  1788. num_clients = int(sys.argv[3])
  1789. if client_id < 1 or client_id > num_clients:
  1790. die('-> Error: client id should be between 1 and the number of clients {0:d}'
  1791. .format(num_clients))
  1792. PNUM += client_id
  1793. else:
  1794. num_clients = 1
  1795. client_id = 1
  1796. output('-> factmsieve.py (v{0:s})'.format(VERSION), console=False)
  1797. t = platform.python_version_tuple()
  1798. print('-> Running Python {0[0]:s}.{0[1]:s}'.format(t))
  1799. output('-> This is client {0:d} of {1:d}'.format(client_id, num_clients))
  1800. output('-> Running on {0:d} Core{1:s} with {2:d} hyper-thread{3:s} per Core'
  1801. .format(NUM_CORES, ('' if NUM_CORES == 1 else 's'),
  1802. THREADS_PER_CORE, ('' if THREADS_PER_CORE == 1 else 's')))
  1803. output('-> Working with NAME = {0:s}'.format(NAME))
  1804. if client_id > 1:
  1805. JOBNAME += '.' + str(client_id)
  1806. SIEVER_OUTPUTNAME += '.' + str(client_id)
  1807. SIEVER_ADDNAME += '.' + str(client_id)
  1808. check_binary(MSIEVE)
  1809. # Is there a poly file already, or do we need to create one?
  1810. if not os.path.exists(NAME + '.poly'):
  1811. if os.path.exists(NAME + '.fb'):
  1812. output('-> Converting msieve polynomial (*.fb) to ggnfs (*.poly) format.')
  1813. fb_to_poly()
  1814. elif not os.path.exists(NAME + '.n'):
  1815. die('-> Could not find the file {0:s}.n'.format(NAME))
  1816. else:
  1817. delete_file(PARAMFILE)
  1818. with open(NAME + '.n', 'r') as in_f:
  1819. numberinf = in_f.readlines()
  1820. t = grep_l('^n:', numberinf)
  1821. if len(t):
  1822. m = re.search('n:\s*(\d+)', t[0])
  1823. if len(t) and m and len(m.group(1)):
  1824. fact_p['n'] = int(m.group(1))
  1825. fact_p['dec_digits'] = len(m.group(1))
  1826. print('-> Found n = {0:d}.'.format(fact_p['n']))
  1827. else:
  1828. output('-> Could not find a number in the file {0:s}.n'.format(NAME))
  1829. die('-> Did you forget the \'n:\' tag?')
  1830. if probable_prime_p(fact_p['n'], 10):
  1831. die ('-> Error: n is probably prime!')
  1832. if fact_p['n'] >= 2 ** MIN_NFS_BITS:
  1833. poly_start = time.time()
  1834. print('-> Polynomial file {0:s}.poly does not exist!'.format(NAME))
  1835. if num_clients > 1:
  1836. die('-> Script does not support polynomial search across multiple clients!')
  1837. output('-> Running polynomial selection ...')
  1838. if fact_p['dec_digits'] < 98:
  1839. USE_KLEINJUNG_FRANKE_PS = 0
  1840. if USE_KLEINJUNG_FRANKE_PS:
  1841. run_pol5(fact_p, pol5_p, lats_p, clas_p)
  1842. elif USE_MSIEVE_POLY:
  1843. if not run_msieve_poly(fact_p, POLY_MIN_LC, POLY_MAX_LC):
  1844. sys.exit(0)
  1845. else:
  1846. run_poly_select(fact_p, pols_p, lats_p, clas_p)
  1847. if not os.path.exists(NAME + '.poly'):
  1848. die('Polynomial selection failed.')
  1849. poly_time = time.time() - poly_start
  1850. else:
  1851. output('-> Running mpqs')
  1852. fact_p['type'] = 'mpqs'
  1853. if msieve_mpqs(fact_p):
  1854. output_summary(NAME, fact_p, pols_p, poly_p, lats_p)
  1855. sys.exit(0)
  1856. # Read and verify parameters for the factorization.
  1857. if not os.path.exists(NAME + '.poly'):
  1858. die('Cannot find {0:s}.poly'.format(NAME))
  1859. read_parameters(fact_p, poly_p, lats_p)
  1860. check_parameters(fact_p, poly_p, lats_p)
  1861. if not os.path.exists(DEPFNAME):
  1862. output('-> Running setup ...')
  1863. setup(fact_p, poly_p, lats_p, client_id, num_clients, SV_THREADS)
  1864. # Do some classical sieving, if needed/applicable.
  1865. if client_id > 1:
  1866. DOCLASSICAL = 0
  1867. if DOCLASSICAL:
  1868. output('-> Running classical siever ...')
  1869. run_classical_sieve(clas_p['cl_a'], 1, clas_p['cl_b'])
  1870. # Finally, sieve until we have reached the desired min # of FF's.
  1871. output('-> Running lattice siever ...')
  1872. run_siever(client_id, num_clients, SV_THREADS, fact_p, lats_p)
  1873. if client_id > 1:
  1874. print('Client {0:d} terminating...'.format(client_id))
  1875. sys.exit(0)
  1876. # Obviously, the matrix solving step.
  1877. if not os.path.exists(DEPFNAME):
  1878. output('-> Running matrix solving step ...')
  1879. ret = run_msieve('-t {0:d} -nc2'.format(LA_THREADS))
  1880. if ret:
  1881. die('Return value {0:d}. Terminating...'.format(ret))
  1882. if not os.path.exists(DEPFNAME):
  1883. die('Some error occurred and matsolve did not record dependencies.')
  1884. else:
  1885. print('-> File \'deps\' already exists. Proceeding to sqrt step.')
  1886. # Do as many square root jobs as needed to get the final factorization
  1887. if not os.path.exists(summary_name(NAME, fact_p)):
  1888. output('-> Running square root step ...')
  1889. ret = run_msieve('-t {0:d} -nc3'.format(LA_THREADS))
  1890. if CLEANUP:
  1891. for f in glob.iglob('cols*'):
  1892. delete_file(f)
  1893. for f in glob.iglob('deps*'):
  1894. delete_file(f)
  1895. delete_file('factor.easy')
  1896. for f in glob.iglob('rels*'):
  1897. delete_file(f)
  1898. delete_file('spairs.out')
  1899. delete_file('spairs.out.gz')
  1900. delete_file(NAME + '.fb')
  1901. for f in glob.iglob('*.afb.0'):
  1902. delete_file(f)
  1903. delete_file('tmpdata.000')
  1904. delete_file(PARAMFILE)
  1905. output_summary(NAME, fact_p, pols_p, poly_p, lats_p)
  1906. for i in range(5):
  1907. sys.stdout.write('\a')
  1908. sys.stdout.flush()
  1909. time.sleep(0.5)