From c51c6c1fbf63ed122d9d36fcf31a22126ed3cf1e Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Sun, 30 Nov 2014 16:04:43 +0000 Subject: [PATCH] Breaking hill ciphers done, challenge 6 done. --- 2014-challenge6.ipynb | 106 ++++++----------- 2014/4b.ciphertext | 3 +- cipher.py | 2 +- cipherbreak.py | 47 +++++++- hill-ciphers.ipynb | 267 +++++++++++++++++++++++++++++++++++++++++- 5 files changed, 348 insertions(+), 77 deletions(-) diff --git a/2014-challenge6.ipynb b/2014-challenge6.ipynb index ebc0e1f..fc91ef6 100644 --- a/2014-challenge6.ipynb +++ b/2014-challenge6.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:2fd72ba7fe3bce3be5a85e8242c119102b9a08ef8f13a01e1c8f9d30d9474858" + "signature": "sha256:5973034ac2337d403853a03b7c1d5fdb5ce28d6b3ac7e6be40537ee382e9f648" }, "nbformat": 3, "nbformat_minor": 0, @@ -43,7 +43,7 @@ "output_type": "pyout", "prompt_number": 2, "text": [ - "" + "" ] }, { @@ -51,7 +51,7 @@ "output_type": "display_data", "png": "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\n", "text": [ - "" + "" ] } ], @@ -70,9 +70,9 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 11, + "prompt_number": 3, "text": [ - "" + "" ] }, { @@ -80,11 +80,11 @@ "output_type": "display_data", "png": "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\n", "text": [ - "" + "" ] } ], - "prompt_number": 11 + "prompt_number": 3 }, { "cell_type": "code", @@ -99,9 +99,9 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 6, + "prompt_number": 4, "text": [ - "" + "" ] }, { @@ -109,11 +109,11 @@ "output_type": "display_data", "png": "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\ngg==\n", "text": [ - "" + "" ] } ], - "prompt_number": 6 + "prompt_number": 4 }, { "cell_type": "code", @@ -128,13 +128,13 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 7, + "prompt_number": 5, "text": [ "'mtaeglatcleptenopeautelebiiootatwnantateituiiagaeostgvetabdresiacqobwavgrhrsihssaekajbwwttdrsmeetnyafsegilegtkrreocuantteomsgstnsiaeluutrbaiaeteeserhxgtooarrbhpcklialhnaesvearhbepiydcesewtaxuyaerywoeinhteegeisieireaassrbitnhtuorooleewsttereoahyakhlsmsaeodslthsutigqimnidsgetpmwtrnnotfhvselkaumrndvcnrluceryhyeetlnigouncnanrhpnosbhshpslreclvrinfoehniaeennhcrbenrgunruesmlrehiutgteordroeaeoisoeusiknteeslohthdcrmisuteoteaeoshfaiaesemritrseisaigwyrmhrbtetncoenuhorcadeodlcrncomnctosihudtcinagesntisutigytmshthyalatlsnhilguimtlbfldyhrfrnetsaosteetaefhlgokhretcakuteihrlrtlsetshlcpeadhthyutaeennhryraeennihrnbhnsnehyutsdtoywmtiatalwhvbepetlxihuscrtadtikhnxmsaesnwluevgnrcpegvnhteruigeuealsdntikeaeomctwrybusiilephkyodhrsyhecaatrmrltrarretstuoetnuesiduaidoesisaeetbllerpntroisiatsiasesomihsieiaunsaitneelacrfnrnngvetteenslhvpepteonedtnaooutgsotancetimiiwoetiuihclsewtcniieotslfbeecohenpoelsdoctceeemiiirttmhbiuovecegaitjuaborcleentatruyinetsidlaeehitwencceohwvohoatwkteroarhcseer'" ] } ], - "prompt_number": 7 + "prompt_number": 5 }, { "cell_type": "code", @@ -149,19 +149,19 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 3, + "prompt_number": 6, "text": [ "'hwssswxfewhhrfewpdrvttdhxbccleayphalnadhiehaoudrotwnrrvysabjlttbaytmelrkaidopthatlelrtwaamaneksvvzrvllatkcrjquicizgtoqcpnrrkttowandqehtqrvtbaydqealannohulanuzlwextlvjrvivhnohdqmgykaclmswrupdetfioftfelhzpxhaswftwprrsweiseohefpdrvttnvagdvswgoerbetnharvaeevtlltbmgaiatgelinmdawevhatterdhrznbnvoutnefoteveaehlaymhacglzeptvvdimworfisgtuzlwibeqohubtghamqornjnnrumqvjtxeltfovgawdaeevllgrtxibgtibevmpsaateoasevaeyqohameonncfuidoefafattemuimnflznbekofobrliaehhauihnnnwzaeevtlltpaalnanvtzlzuucptaelinanpaahewfthaosetaribnbnvhaevdhyytlmuxb'" ] } ], - "prompt_number": 3 + "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ - "key_a, score = keyword_break_mp(c6a)\n", + "key_a, score = railfence_break(c6as)\n", "key_a, score" ], "language": "python", @@ -170,39 +170,19 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 4, - "text": [ - "(('ad', ), -1231.3855550875928)" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print(' '.join(segment(keyword_decipher(sanitise(c6a), key_a[0], key_a[1]))))" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", + "prompt_number": 7, "text": [ - "mt aegl at dle pte nope aut elec ii oot a twn an tate itu ii a gae ostg vetacbresiadqocwavgr hrsihssaekajcwwttbrs meet nyafsegilegtkrreodu ant teom sgstnsiaeluutrcaiae teese rhxgtooarrchpdklialh naesvearhcepiybdesew tax uyaerywoeinhteegeisi eire a as src it nh tu or ooleewsttereoahyakhl sms aeobslthsutigqimnibs get pm wtr n not fhvselkaumrnbvdnr luder yhyeetlnigoundnanrhp no schs hp sl red lvr info ehniaeennhdrcenrgun rues mlrehiutgteorbroeaeo is oe us ikn tees loh th bdrm is uteoteaeoshfaiaesemr it rse is aigwyrmhrctetndoenuh or da be obldrndomndtosihubtd in ages ntis utigytmshthyalatlsnh il gui mtl cfl by hr fr net sao steet ae fhlgokhretdakuteihrl rtl sets hldpeabhthyutaeennhr yraeennihrnchnsnehyu tsb toy wmtiatalwhvcepetlxih us dr tab tikhnxmsaesnwluevgnr dpegvnhteruigeuealsb nt ikea eo mdt wrycusiilephkyobhrsy he da at rmrltrarretstuoetnue sibu aibo es is ae etc ller pn troisi at sias eso mi hsie i a unsa it neela dr fnr nng vet teens lhv pep te one bt nao out g sot and e tim i iwo et iuihdlsewtdniieotslf cee do hen poels bod tdeeemiiirttmhciuove de gait jua cordle ent a truy in etsi bla ee hit wend de ohwvohoatwkteroarhd seer\n" + "(3, -2314.997881051078)" ] } ], - "prompt_number": 5 + "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ - "key_a, score = column_transposition_break_mp(c6as)\n", - "key_a, score" + "' '.join(segment(railfence_decipher(c6as, key_a)))" ], "language": "python", "metadata": {}, @@ -210,41 +190,20 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 10, + "prompt_number": 8, "text": [ - "(((0, 4, 3, 7, 2, 1, 5, 6, 8), False, True), -2617.4798034835794)" - ] - } - ], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print(' '.join(segment(sanitise(column_transposition_decipher(sanitise(c6as), key_a[0], \n", - " fillcolumnwise=key_a[1], \n", - " emptycolumnwise=key_a[2])))))" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "mferkepsethibrsnbeal sir nth ce gate wr so go in olohhlkghcuipeahw tue ssn try uav ilp cer ongaro ltm rtn tee echo trs clparoecilstkblopavd eu temes ron tees geico et wg vs ntp in ssn of cehctthmoearotntieeu leese hhetrnrirsnmetueauii ill hoe iea ie so algie iberhueaeritcyuuunt is a a tenn to hd krash mole h blach tco las irb a pdsid tbi tel man neu wac set en ondra tier vahneeklgentcoeeauct hods acne aym see rrgtunlrofuaetcthmne ii a thx crs tteosgtnmjuesutwnlu in it or grain hioyvebahugabehogrdq ruti ray tir stu cerc mb i et loa in hi ege seni pln tete ad ces engng sk plot vneglhhraeiseikvdt thn tay prr art plo eoubnimhdpeydbswnht air hut are en entre soo ess in syn it in gnvhessaeyoeedoichtt acted qymfranuloushhaasabt hvb to i ewst serokeadhepmunhvtyli rtti go a kylgetryladtsewhwauc rose rmt meat lnstlrsraociisnernhc hand we c test hv tte hosa i cast d hall nxticwewgruumrvkhuly oimoaviuaeiihjbmcetw so beter no uaw pl ryu ett we by we tew ttfhosioktllyeiuttdx dei die eri yen u harsh hth ace om url tilo a esf nedss rec rieoehhtrnggewfcnteo estas ya tui ici eads nss na efta cia i ersion eei seks a ieee ght nr to miner ebtrlxehalsiemtp all tg sans ef rta eos rbs\n" + "'mark the last message told usa lot the scuttling equipment is designed to pump water in and out of the vessel like a submarine dive control but clearly they werent planning to turn a container ship into a sub this ship is a largescale version of something i have seen in the caribbean drug runners use a similar technique to get below radar coverage for inshore runs sinking the vessel so that the deck remains just below the wave tops the fda pirates seem more interested in staying away from shore but getting close enough to track and record electronic communications without detection i am guessing this scuttling system is what they call nautilus in their log but i am still baffled by the references to seahorse the next page of the log looks harder to crack but the cipher clerk tells me it is a hill cipher and that they must have been in a hurry or have been enciphering by hand since they just used a two by two matrix actually we have been pretty lax with our security and i think the next message is end will use avi genere cipher given that we are using secure cables i dont think we have too much to worry about so i will keep the keyword short say three characters more later harry'" ] } ], - "prompt_number": 13 + "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ - "key_a, score = railfence_break(c6as)\n", - "key_a, score" + "key_b, score = hill_break(c6bs)\n", + "key_b, score" ], "language": "python", "metadata": {}, @@ -252,19 +211,20 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 16, + "prompt_number": 14, "text": [ - "(3, -2314.997881051078)" + "(matrix([[0, 1],\n", + " [1, 1]]), -666.1299098341699)" ] } ], - "prompt_number": 16 + "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": [ - "' '.join(segment(railfence_decipher(c6as, key_a)))" + "' '.join(segment(hill_decipher(key_b, c6bs)))" ], "language": "python", "metadata": {}, @@ -272,13 +232,13 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 17, + "prompt_number": 13, "text": [ - "'mark the last message told usa lot the scuttling equipment is designed to pump water in and out of the vessel like a submarine dive control but clearly they werent planning to turn a container ship into a sub this ship is a largescale version of something i have seen in the caribbean drug runners use a similar technique to get below radar coverage for inshore runs sinking the vessel so that the deck remains just below the wave tops the fda pirates seem more interested in staying away from shore but getting close enough to track and record electronic communications without detection i am guessing this scuttling system is what they call nautilus in their log but i am still baffled by the references to seahorse the next page of the log looks harder to crack but the cipher clerk tells me it is a hill cipher and that they must have been in a hurry or have been enciphering by hand since they just used a two by two matrix actually we have been pretty lax with our security and i think the next message is end will use avi genere cipher given that we are using secure cables i dont think we have too much to worry about so i will keep the keyword short say three characters more later harry'" + "'phase six seahorse operated exactly as planned with good forward visibility at the trial depths the crew managed several tasks requiring concentration and dexterity and we plan to run a full test overnight on dummy cables dropped from the ship the software seems to be operating as designed but there are still bugs in the firmware that need ironing out before we deploy the collective is working full time to hunt them down and remove them though we are all getting tired mistakes are easy to make and could be fatal time is no longer on our side though and we are still planning to launch the final phase of the operation in three days timex'" ] } ], - "prompt_number": 17 + "prompt_number": 13 }, { "cell_type": "code", diff --git a/2014/4b.ciphertext b/2014/4b.ciphertext index cf2c74b..cd9848f 100644 --- a/2014/4b.ciphertext +++ b/2014/4b.ciphertext @@ -1 +1,2 @@ -PRSAO EGERA UIADM WEHDN ISNRA SAWUA AESSR EFGDO SOGVO RBEEE AARTE SCTDF MENUI BRTTL MEYTU MTMEU AIKWH UTKWE RWAHM NPWRA EESON ONESE BATOI HACIN EETBR OTADA KTGFE ESYIO FLTTL STIIA EOSVI EONSR RTAUP MNNOA ENCOC NUVRS CLVDR GCTAI IHRIC IAIHR SDUOM RLEMC RNGLE OMARF HIUEW HALCS ASRAC UFRAW WSMEH ULSTO AOHCE LETMT OILSE PDMUM TPTRS LYRHH NTPAN WPMOA DPPDW BESEO ASSLT MLPES LETUN CORER LCLIT AOSVS INIIF WSEAF ORTAA DUYEN ENONN SOPFH ONTWK OERTC SLYVO EIOHL UFOEI OETST HTSBR ENEVE AOUEP GIEES OBDUO RSFEE RCDYA DUTAE PEADR DIGSE EBFUO GGOPO GALYF EWSOE EMDNT OHREB HAAES NEWOR GNFIA ULNLW ADUEO DCOTR ARGVU ENEWH IERTL AUILM SONIO TMUIN EWAIU EWLOE RSTTT ISDRS ASNUS SIESM ERDHE TRYRH PNLRT EREAD MREDE BNNTR NENWM OUTRD OSANE OWOMC GIDCI ASAON TIIOI ASCES ISSUP CRMOY BRINE YWEEL AYLEW TYRTI LHSTO \ No newline at end of file +PRSAO EGERA UIADM WE +HDN ISNRA SAWUA AESSR EFGDO SOGVO RBEEE AARTE SCTDF MENUI BRTTL MEYTU MTMEU AIKWH UTKWE RWAHM NPWRA EESON ONESE BATOI HACIN EETBR OTADA KTGFE ESYIO FLTTL STIIA EOSVI EONSR RTAUP MNNOA ENCOC NUVRS CLVDR GCTAI IHRIC IAIHR SDUOM RLEMC RNGLE OMARF HIUEW HALCS ASRAC UFRAW WSMEH ULSTO AOHCE LETMT OILSE PDMUM TPTRS LYRHH NTPAN WPMOA DPPDW BESEO ASSLT MLPES LETUN CORER LCLIT AOSVS INIIF WSEAF ORTAA DUYEN ENONN SOPFH ONTWK OERTC SLYVO EIOHL UFOEI OETST HTSBR ENEVE AOUEP GIEES OBDUO RSFEE RCDYA DUTAE PEADR DIGSE EBFUO GGOPO GALYF EWSOE EMDNT OHREB HAAES NEWOR GNFIA ULNLW ADUEO DCOTR ARGVU ENEWH IERTL AUILM SONIO TMUIN EWAIU EWLOE RSTTT ISDRS ASNUS SIESM ERDHE TRYRH PNLRT EREAD MREDE BNNTR NENWM OUTRD OSANE OWOMC GIDCI ASAON TIIOI ASCES ISSUP CRMOY BRINE YWEEL AYLEW TYRTI LHSTO \ No newline at end of file diff --git a/cipher.py b/cipher.py index cd75d2c..91e64e5 100644 --- a/cipher.py +++ b/cipher.py @@ -656,7 +656,6 @@ def hill_encipher(matrix, message_letters, fillvalue='a'): return ''.join([chr(int(round(l)) % 26 + ord('a')) for l in sum(enciphered_chunks, [])]) - def hill_decipher(matrix, message, fillvalue='a'): """Hill cipher @@ -671,6 +670,7 @@ def hill_decipher(matrix, message, fillvalue='a'): inverse_matrix = (inverse_determinant * adjoint) % 26 return hill_encipher(inverse_matrix, message, fillvalue) + class PocketEnigma(object): """A pocket enigma machine The wheel is internally represented as a 26-element list self.wheel_map, diff --git a/cipherbreak.py b/cipherbreak.py index e563b81..b1af48c 100644 --- a/cipherbreak.py +++ b/cipherbreak.py @@ -416,6 +416,19 @@ def scytale_break_mp(message, max_key_length=20, scytale_break = scytale_break_mp +def railfence_break(message, max_key_length=20, + fitness=Pletters, chunksize=500): + """Breaks a hill cipher using a matrix of given rank and letter frequencies + + + """ + + sanitised_message = sanitise(message) + results = starmap(worker, [(sanitised_message, i, fitness) + for i in range(2, max_key_length+1)]) + return max(results, key=lambda k: k[1]) + + def railfence_break(message, max_key_length=20, fitness=Pbigrams, chunksize=500): """Breaks a railfence cipher using a range of lengths and @@ -445,13 +458,45 @@ def railfence_break(message, max_key_length=20, plaintext = railfence_decipher(message, height) fit = fitness(plaintext) return height, fit - + sanitised_message = sanitise(message) results = starmap(worker, [(sanitised_message, i, fitness) for i in range(2, max_key_length+1)]) return max(results, key=lambda k: k[1]) +def hill_break(message, matrix_size=2, fitness=Pletters, + number_of_solutions=1, chunksize=500): + + all_matrices = [np.matrix(list(m)) + for m in itertools.product([list(r) + for r in itertools.product(range(26), repeat=matrix_size)], + repeat=matrix_size)] + valid_matrices = [m for m, d in + zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices)) + if d != 0 + if d % 2 != 0 + if d % 13 != 0 ] + with Pool() as pool: + helper_args = [(message, matrix, fitness) + for matrix in valid_matrices] + # Gotcha: the helper function here needs to be defined at the top level + # (limitation of Pool.starmap) + breaks = pool.starmap(hill_break_worker, helper_args, chunksize) + if number_of_solutions == 1: + return max(breaks, key=lambda k: k[1]) + else: + return sorted(breaks, key=lambda k: k[1], reverse=True)[:number_of_solutions] + +def hill_break_worker(message, matrix, fitness): + plaintext = hill_decipher(matrix, message) + fit = fitness(plaintext) + logger.debug('Hill cipher break attempt using key {0} gives fit of ' + '{1} and decrypt starting: {2}'.format(matrix, + fit, sanitise(plaintext)[:50])) + return matrix, fit + + def pocket_enigma_break_by_crib(message, wheel_spec, crib, crib_position): """Break a pocket enigma using a crib (some plaintext that's expected to be in a certain position). Returns a list of possible starting wheel diff --git a/hill-ciphers.ipynb b/hill-ciphers.ipynb index 909828a..2019dd5 100644 --- a/hill-ciphers.ipynb +++ b/hill-ciphers.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:0fe9165e4a65606dd93377df5e8d4ccf8671a4edf4adc8d5da4b33f83316516f" + "signature": "sha256:112d1c84c318592f927e18c5b0f15ed60ac8418ca15cb79596ba6212ff2d7e3f" }, "nbformat": 3, "nbformat_minor": 0, @@ -1377,6 +1377,271 @@ ], "prompt_number": 184 }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "len([list(m) for m in itertools.product([list(r) for r in itertools.product(range(26), repeat=3)], repeat=3)])" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "pyerr", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "prompt_number": 203 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "(3**3)**3" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 202, + "text": [ + "19683" + ] + } + ], + "prompt_number": 202 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "[np.matrix(list(m)) for m in itertools.product([list(r) for r in itertools.product(range(3), repeat=2)], repeat=2)]" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 206, + "text": [ + "[matrix([[0, 0],\n", + " [0, 0]]), matrix([[0, 0],\n", + " [0, 1]]), matrix([[0, 0],\n", + " [0, 2]]), matrix([[0, 0],\n", + " [1, 0]]), matrix([[0, 0],\n", + " [1, 1]]), matrix([[0, 0],\n", + " [1, 2]]), matrix([[0, 0],\n", + " [2, 0]]), matrix([[0, 0],\n", + " [2, 1]]), matrix([[0, 0],\n", + " [2, 2]]), matrix([[0, 1],\n", + " [0, 0]]), matrix([[0, 1],\n", + " [0, 1]]), matrix([[0, 1],\n", + " [0, 2]]), matrix([[0, 1],\n", + " [1, 0]]), matrix([[0, 1],\n", + " [1, 1]]), matrix([[0, 1],\n", + " [1, 2]]), matrix([[0, 1],\n", + " [2, 0]]), matrix([[0, 1],\n", + " [2, 1]]), matrix([[0, 1],\n", + " [2, 2]]), matrix([[0, 2],\n", + " [0, 0]]), matrix([[0, 2],\n", + " [0, 1]]), matrix([[0, 2],\n", + " [0, 2]]), matrix([[0, 2],\n", + " [1, 0]]), matrix([[0, 2],\n", + " [1, 1]]), matrix([[0, 2],\n", + " [1, 2]]), matrix([[0, 2],\n", + " [2, 0]]), matrix([[0, 2],\n", + " [2, 1]]), matrix([[0, 2],\n", + " [2, 2]]), matrix([[1, 0],\n", + " [0, 0]]), matrix([[1, 0],\n", + " [0, 1]]), matrix([[1, 0],\n", + " [0, 2]]), matrix([[1, 0],\n", + " [1, 0]]), matrix([[1, 0],\n", + " [1, 1]]), matrix([[1, 0],\n", + " [1, 2]]), matrix([[1, 0],\n", + " [2, 0]]), matrix([[1, 0],\n", + " [2, 1]]), matrix([[1, 0],\n", + " [2, 2]]), matrix([[1, 1],\n", + " [0, 0]]), matrix([[1, 1],\n", + " [0, 1]]), matrix([[1, 1],\n", + " [0, 2]]), matrix([[1, 1],\n", + " [1, 0]]), matrix([[1, 1],\n", + " [1, 1]]), matrix([[1, 1],\n", + " [1, 2]]), matrix([[1, 1],\n", + " [2, 0]]), matrix([[1, 1],\n", + " [2, 1]]), matrix([[1, 1],\n", + " [2, 2]]), matrix([[1, 2],\n", + " [0, 0]]), matrix([[1, 2],\n", + " [0, 1]]), matrix([[1, 2],\n", + " [0, 2]]), matrix([[1, 2],\n", + " [1, 0]]), matrix([[1, 2],\n", + " [1, 1]]), matrix([[1, 2],\n", + " [1, 2]]), matrix([[1, 2],\n", + " [2, 0]]), matrix([[1, 2],\n", + " [2, 1]]), matrix([[1, 2],\n", + " [2, 2]]), matrix([[2, 0],\n", + " [0, 0]]), matrix([[2, 0],\n", + " [0, 1]]), matrix([[2, 0],\n", + " [0, 2]]), matrix([[2, 0],\n", + " [1, 0]]), matrix([[2, 0],\n", + " [1, 1]]), matrix([[2, 0],\n", + " [1, 2]]), matrix([[2, 0],\n", + " [2, 0]]), matrix([[2, 0],\n", + " [2, 1]]), matrix([[2, 0],\n", + " [2, 2]]), matrix([[2, 1],\n", + " [0, 0]]), matrix([[2, 1],\n", + " [0, 1]]), matrix([[2, 1],\n", + " [0, 2]]), matrix([[2, 1],\n", + " [1, 0]]), matrix([[2, 1],\n", + " [1, 1]]), matrix([[2, 1],\n", + " [1, 2]]), matrix([[2, 1],\n", + " [2, 0]]), matrix([[2, 1],\n", + " [2, 1]]), matrix([[2, 1],\n", + " [2, 2]]), matrix([[2, 2],\n", + " [0, 0]]), matrix([[2, 2],\n", + " [0, 1]]), matrix([[2, 2],\n", + " [0, 2]]), matrix([[2, 2],\n", + " [1, 0]]), matrix([[2, 2],\n", + " [1, 1]]), matrix([[2, 2],\n", + " [1, 2]]), matrix([[2, 2],\n", + " [2, 0]]), matrix([[2, 2],\n", + " [2, 1]]), matrix([[2, 2],\n", + " [2, 2]])]" + ] + } + ], + "prompt_number": 206 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "all_matrices = [np.matrix(list(m)) for m in itertools.product([list(r) for r in itertools.product(range(26), repeat=2)], repeat=2)]\n", + "valid_matrices = [m for m, d in zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices))\n", + " if d != 0\n", + " if d % 2 != 0\n", + " if d % 13 != 0 ]\n", + "len(valid_matrices)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 215, + "text": [ + "157248" + ] + } + ], + "prompt_number": 215 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%%timeit\n", + "[m for m, d in zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices))\n", + " if d != 0\n", + " if d % 2 != 0\n", + " if d % 13 != 0 ]\n", + "print('done')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "done\n", + "done" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + "done" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + "done" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + "1 loops, best of 3: 10 s per loop\n" + ] + } + ], + "prompt_number": 216 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%%timeit\n", + "[m for m in all_matrices\n", + " if int(round(linalg.det(m))) != 0\n", + " if int(round(linalg.det(m))) % 2 != 0\n", + " if int(round(linalg.det(m))) % 13 != 0 ]\n", + "print('done')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "done\n", + "done" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + "done" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + "done" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + "1 loops, best of 3: 20.4 s per loop\n" + ] + } + ], + "prompt_number": 217 + }, { "cell_type": "code", "collapsed": false, -- 2.34.1