CJam, 189 187 bayt
Bunu açıklamak zor olacak ... Zamanın karmaşıklığı garanti edilir O(scary)
.
qi:N_3>{,aN*]N({{:L;N,X)-e!{X)_@+L@@t}%{X2+<z{_fe=:(:+}%:+!},}%:+}fX{:G;N3m*{_~{G@==}:F~F\1m>~F\F=}%:*},:L,({LX=LX)>1$f{\_@a\a+Ne!\f{\:M;~{M\f=z}2*\Mff==}:|{;}|}\a+}fX]:~$e`{0=1=},,}{!!}?
Yeterince cesursanız, çevrimiçi deneyin . Berbat dizüstü bilgisayarımda Java tercümanı ile 6'ya veya çevrimiçi tercümandan 5'e kadar alabilirim.
açıklama
Büyük bir matematik geçmişim yok (liseyi yeni bitirdim, CS'ye gelecek hafta üniversitede başlıyor). Öyleyse eğer hata yaparsam, açıkça söylersem ya da korkunç derecede etkisiz şekillerde şeyler yaparsam, yanımda ol.
Benim yaklaşımım kaba bir kuvvettir, ancak biraz daha zeki yapmaya çalıştım. Ana adımlar:
- Tüm olası işleçleri ∗ bir grup n için üretin (yani, tüm n gruplarını numaralandırın );
- Olası bijections tüm üret j düzenin iki grup arasında n ;
- Adım 1 ve 2'deki sonuçları kullanarak, iki sıra grubu n arasındaki tüm izomorfizmleri belirleyin ;
- 3. adımdaki sonucu kullanarak, izomorfizme kadar olan grup sayısını sayın.
Her adımın nasıl yapıldığına bakmadan önce, yoldan bazı önemsiz kodlar alalım:
qi:N_ e# Get input as integer, store in N, make a copy
3>{...} ? e# If N > 3, do... (see below)
{!!} e# Else, push !!N (0 if N=0, 1 otherwise)
Aşağıdaki algoritma n <4 ile düzgün çalışmıyor , 0 ila 3 arasındaki durumlar çift olumsuzlama ile ele alınıyor.
Şu andan itibaren, bir grubun elemanları {1, a, b, c, ...} şeklinde yazılacaktır , burada 1 kimlik elemanıdır. CJam uygulamasında, karşılık gelen elemanlar {0, 1, 2, 3, ...} olup , burada 0 , kimlik elemanıdır.
Let emri grubu için tüm olası operatörleri Yazma 1. adımdan itibaren başlamak n tüm geçerli üreten eşdeğerdir n × n Cayley tablolar . İlk satır ve sütun önemsiz: her ikisi de {1, a, b, c, ...} (soldan sağa, yukarıdan aşağıya).
e# N is on the stack (duplicated before the if)
,a e# Generate first row [0 1 2 3 ...] and wrap it in a list
N* e# Repeat row N times (placeholders for next rows)
] e# Wrap everything in a list
e# First column will be taken care of later
Bir Cayley tablasının da azaltılmış bir Latin karesi olduğunu bilmek (iptal etme özelliğinden dolayı) sırayla olası tabloların oluşturulmasına izin verir. İkinci satırdan başlayarak (dizin 1), ilk sütunu dizinin değerine sabit tutmak için o satır için tüm benzersiz izinleri oluştururuz .
N({ }fX e# For X in [0 ... N-2]:
{ }% e# For each table in the list:
:L; e# Assign the table to L and pop it off the stack
N, e# Push [0 ... N-1]
X) e# Push X+1
- e# Remove X+1 from [0 ... N-1]
e! e# Generate all the unique permutations of this list
{ }% e# For each permutation:
X)_ e# Push two copies of X+1
@+ e# Prepend X+1 to the permutation
L@@t e# Store the permutation at index X+1 in L
{...}, e# Filter permutations (see below)
:+ e# Concatenate the generated tables to the table list
Elbette ki tüm bu permütasyonlar geçerli değildir: her satır ve sütun tüm elemanları bir kez içermelidir. Bu amaçla bir filtre bloğu kullanılır (gerçek bir değer permütasyonu tutar, sahte bir tanesi onu kaldırır):
X2+ e# Push X+2
< e# Slice the permutations to the first X+2 rows
z e# Transpose rows and columns
{ }% e# For each column:
_fe= e# Count occurences of each element
:( e# Subtract 1 from counts
:+ e# Sum counts together
:+ e# Sum counts from all columns together
! e# Negate count sum:
e# if the sum is 0 (no duplicates) the permutation is kept
e# if the sum is not zero the permutation is filtered away
Üretim döngüsünün içine filtre uyguladığımı unutmayın: bu, kodu biraz daha uzun yapar (farklı oluşturma ve filtrelemeye kıyasla), ancak performansı büyük ölçüde artırır. Boyut kümesi permütasyon sayısı n olan n! , bu yüzden kısa çözüm çok fazla hafıza ve zaman gerektirecektir.
Geçerli Cayley tablolarının listesi operatörleri numaralandırmaya doğru atılmış büyük bir adımdır, ancak 2B yapı olduğundan, 3B özelliği olan ilişkilendirmeyi kontrol edemez. Yani bir sonraki adım ilişkisel olmayan fonksiyonları filtrelemektir.
{ }, e# For each table, keep table if result is true:
:G; e# Store table in G, pop it off the stack
N3m* e# Generate triples [0 ... N-1]^3
{ }% e# For each triple [a b c]:
_~ e# Make a copy, unwrap top one
{ }:F e# Define function F(x,y):
G@== e# x∗y (using table G)
~F e# Push a∗(b∗c)
\1m> e# Rotate triple right by 1
~ e# Unwrap rotated triple
F\F e# Push (a∗b)∗c
= e# Push 1 if a∗(b∗c) == (a∗b)∗c (associative), 0 otherwise
:* e# Multiply all the results together
e# 1 (true) only if F was associative for every [a b c]
Uf! Çok fazla iş, ama şimdi tüm n sıra gruplarını sıraladık (ya da daha iyisi, üzerindeki işlemler - ancak küme sabittir, yani aynı şey). Sonraki adım: izomorfizmleri bulun. Bir izomorfizm, bu iki grup arasında ∗ (x ∗ y) = φ (x) ∗ ∗ (y) şeklinde bir çekişmedir . CJam'da bu teklifleri oluşturmak önemsiz: Ne!
bunu yapacak. Onları nasıl kontrol edebiliriz? Çözümüm, x ∗ y için Cayley tablasının iki kopyasından başlıyor . Bir kopyada φ , tüm öğelere, satır veya sütunların sırasına dokunmadan uygulanır. Bu, φ (x ∗ y) için tablo oluşturur . Oldukları gibi diğer birinde elemanları bırakılır, ancak satırlar ve sütunlar aracılığıyla eşlenir cp . Yani, satır / sütunx satır / sütun x (x) olur . Bu, φ (x) ∗ φ (y) için tablo oluşturur . Şimdi iki tabloya sahip olduğumuza göre, onları karşılaştırmalıyız: eğer aynılarsa, bir izomorfizm bulduk.
Elbette, izomorfizmi test etmek için grup çiftleri oluşturmamız gerekiyor. Grupların bütün 2 kombinasyonuna ihtiyacımız var . Görünüşe göre CJam, kombinasyonlar için operatöre sahip değil. Bunları her grubu alarak ve yalnızca listedeki takip eden öğelerle birleştirerek üretebiliriz. Eğlenceli gerçek: 2 kombinasyon sayısı n × (n - 1) / 2'dir , bu aynı zamanda ilk n - 1 doğal sayının toplamıdır . Bu sayılara üçgen sayı denir: kağıttaki algoritmayı deneyin, her sabit eleman için bir satır ve nedenini göreceksiniz.
:L e# List of groups is on stack, store in L
,( e# Push len(L)-1
{ }fX e# For X in [0 ... len(L)-2]:
LX= e# Push the group L[X]
LX)> e# Push a slice of L excluding the first X+1 elements
1$ e# Push a copy of L[X]
f{...} e# Pass each [L[X] Y] combination to ... (see below)
e# The block will give back a list of Y for isomorphic groups
\a+ e# Append L[X] to the isomorphic groups
] e# Wrap everything in a list
Düzeltmeleri Yukarıdaki kod çiftinin, ilk elemanı L [X] , ve diğer gruplarla birleştirir (edelim bu her bir çağrı Y ). Parite, birazdan göstereceğim izomorfizm test bloğuna geçer. Blok değerlerinin bir listesini geri verir Y olan L [X] izomorf Y . Daha sonra bu listeye L [X] eklenir. Listelerin neden bu şekilde ayarlandığını anlamadan önce, izomorfizm testine bakalım:
\_@ e# Push a copy of Y
a\a+ e# L[X] Y -> [L[X] Y]
Ne! e# Generate all bijective mappings
\f{ } e# For each bijection ([L[X] Y] extra parameter):
\:M; e# Store the mapping in M, pop it off the stack
~ e# [L[X] Y] -> L[X] Y
{ }2* e# Repeat two times (on Y):
M\f= e# Map rows (or transposed columns)
z e# Transpose rows and columns
e# This generates φ(x) ∗ φ(y)
\Mff= e# Map elements of L[X], generates φ(x ∗ y)
= e# Push 1 if the tables are equal, 0 otherwise
:| e# Push 1 if at least a mapping was isomorphic, 0 otherwise
{;}| e# If no mapping was isomorphic, pop the copy of Y off the stack
Harika, şimdi [{L [0], Y1, Y2, ...}, {L [1], Y1, ...}, ...] gibi setlerin bir listesi var . Buradaki fikir, herhangi bir iki kümenin ortak olarak en az bir elemente sahip olması durumunda, geçiş özelliğine göre, iki kümedeki tüm grupların izomorfik olmasıdır. Tek bir sette toplanabilirler. As L [X] tarafından oluşturulan kombinasyonlarda asla görünmeyeceğini L [X + ...] , izomorfizmleri her set toplayarak ardına benzersiz yüzeyi olacak. Bu nedenle, izomorfizm sayısını elde etmek için, tüm izomorf gruplarında kaç grubun tam olarak bir kez göründüğünü saymak yeterlidir. Bunu yapmak için, setleri açarım, böylece [L [0], Y1, Y2, ..., L [1], Y1, ...] gibi görünürler , aynı grubun kümelerini oluşturmak için listeyi sıralarlar ve en sonunda RLE kodla.
:~ e# Unwrap sets of isomorphic groups
$ e# Sort list
e` e# RLE-encode list
{ }, e# Filter RLE elements:
0= e# Get number of occurrences
1= e# Keep element if occurrences == 1
, e# Push length of filtered list
e# This is the number of groups up to isomorphism
Hepsi bu kadar millet.