Python'da bunu istediğiniz dilde cevaplayacak kadar bilgili değil, ancak C / C ++ 'da, sorunuzun parametreleri göz önüne alındığında, sıfırları ve olanları bitlere dönüştürüp uint64_t'nin en az önemli bitlerine iterdim. Bu, 55 bitin hepsini bir düşme taklidi ile karşılaştırmanıza olanak tanır - 1 saat.
Çok hızlı ve her şey çipli önbelleklere (209.880 bayt) sığacak. 55 liste üyesinin tümünü aynı anda kaydırmak için donanım desteği yalnızca CPU kayıtlarında mevcuttur. Aynı şey 55 üyenin tümünü aynı anda karşılaştırmak için de geçerlidir. Bu, sorunun bir yazılım çözümü ile bire bir eşlenmesini sağlar. (ve gerekirse SIMD / SSE 256 bit kayıtlarını kullanarak 256 üyeye kadar) Sonuç olarak kod okuyucu tarafından hemen anlaşılır.
Bunu Python'da uygulayabilirsiniz, bunun mümkün olup olmadığını veya performansın ne olabileceğini bilmek için yeterince iyi bilmiyorum.
Üzerinde uyuduktan sonra birkaç şey belirginleşti ve hepsi daha iyisi için.
1.) Dali'nin akıllıca numarasına gerek duymadan dairesel olarak bağlı listeyi bitler kullanarak döndürmek o kadar kolay ki. 64 bitlik bir kayıtta standart bit kaydırma işlemi, dönüşü çok basit bir şekilde gerçekleştirir ve bit ops yerine aritmetik kullanarak bunu daha Python dostu hale getirmeye çalışır.
2.) Bit kaydırma 2'ye bölünerek kolayca yapılabilir.
3.) Listenin sonunun 0 veya 1 olup olmadığını kontrol etmek modulo 2 ile kolayca yapılabilir.
4.) Bir 0'ı listenin başından kuyruğa "taşımak", 2'ye bölünerek yapılabilir. Bu, eğer sıfır gerçekten hareket ettirilirse, 55. biti yanlış yapar, ki zaten hiçbir şey yapmaz.
5.) a 1'in listenin başından kuyruğa "taşınması" 2'ye bölünerek ve 55. bit doğru ve geri kalan tüm yanlışları işaretleyerek yaratılan değer olan 18,014,398,509,481,984 eklenerek yapılabilir.
6.) Herhangi bir döndürmeden sonra çapanın ve uint64_t öğesinin karşılaştırması TRUE ise, TRUE değerini kesin ve döndürün.
Tekrar tekrar dönüşüm yapmak zorunda kalmamak için listelerin tüm dizisini uint64_ts dizisinin hemen önüne dönüştürürdüm.
Kodu optimize etmek için birkaç saat geçirdikten sonra, montaj dilini inceleyerek çalışma süresinde% 20 tıraş edebildim. O / S ve MSVC derleyicisinin dün gün ortasında da güncellendiğini eklemeliyim. Hangi nedenle olursa olsun, C derleyicisinin ürettiği kodun kalitesi, güncellemeden sonra önemli ölçüde arttı (15/11/2014). Çalışma zamanı artık ~ 70 saat, bir çapa halkası oluşturmak ve bir test halkasının 55 turunun hepsini karşılaştırmak için 17 nanosaniyedir ve tüm halkaların diğerlerine karşı NxN'si 12.5 saniyede yapılır .
Bu kod o kadar sıkı ki 4 kayıt dışında% 99 hiçbir şey yapmadan oturuyorlar. Montaj dili, C kodunu neredeyse satır için eşleştirir. Okuması ve anlaması çok kolay. Birisi kendisine bunu öğretiyor olsaydı harika bir montaj projesi.
Donanım, Hazwell i7, MSVC 64 bit, tam optimizasyonlardır.
#include "stdafx.h"
#include "stdafx.h"
#include <string>
#include <memory>
#include <stdio.h>
#include <time.h>
const uint8_t LIST_LENGTH = 55; // uint_8 supports full witdth of SIMD and AVX2
// max left shifts is 32, so must use right shifts to create head_bit
const uint64_t head_bit = (0x8000000000000000 >> (64 - LIST_LENGTH));
const uint64_t CPU_FREQ = 3840000000; // turbo-mode clock freq of my i7 chip
const uint64_t LOOP_KNT = 688275225; // 26235^2 // 1000000000;
// ----------------------------------------------------------------------------
__inline uint8_t is_circular_identical(const uint64_t anchor_ring, uint64_t test_ring)
{
// By trial and error, try to synch 2 circular lists by holding one constant
// and turning the other 0 to LIST_LENGTH positions. Return compare count.
// Return the number of tries which aligned the circularly identical rings,
// where any non-zero value is treated as a bool TRUE. Return a zero/FALSE,
// if all tries failed to find a sequence match.
// If anchor_ring and test_ring are equal to start with, return one.
for (uint8_t i = LIST_LENGTH; i; i--)
{
// This function could be made bool, returning TRUE or FALSE, but
// as a debugging tool, knowing the try_knt that got a match is nice.
if (anchor_ring == test_ring) { // test all 55 list members simultaneously
return (LIST_LENGTH +1) - i;
}
if (test_ring % 2) { // ring's tail is 1 ?
test_ring /= 2; // right-shift 1 bit
// if the ring tail was 1, set head to 1 to simulate wrapping
test_ring += head_bit;
} else { // ring's tail must be 0
test_ring /= 2; // right-shift 1 bit
// if the ring tail was 0, doing nothing leaves head a 0
}
}
// if we got here, they can't be circularly identical
return 0;
}
// ----------------------------------------------------------------------------
int main(void) {
time_t start = clock();
uint64_t anchor, test_ring, i, milliseconds;
uint8_t try_knt;
anchor = 31525197391593472; // bits 55,54,53 set true, all others false
// Anchor right-shifted LIST_LENGTH/2 represents the average search turns
test_ring = anchor >> (1 + (LIST_LENGTH / 2)); // 117440512;
printf("\n\nRunning benchmarks for %llu loops.", LOOP_KNT);
start = clock();
for (i = LOOP_KNT; i; i--) {
try_knt = is_circular_identical(anchor, test_ring);
// The shifting of test_ring below is a test fixture to prevent the
// optimizer from optimizing the loop away and returning instantly
if (i % 2) {
test_ring /= 2;
} else {
test_ring *= 2;
}
}
milliseconds = (uint64_t)(clock() - start);
printf("\nET for is_circular_identical was %f milliseconds."
"\n\tLast try_knt was %u for test_ring list %llu",
(double)milliseconds, try_knt, test_ring);
printf("\nConsuming %7.1f clocks per list.\n",
(double)((milliseconds * (CPU_FREQ / 1000)) / (uint64_t)LOOP_KNT));
getchar();
return 0;
}
