Đếm các nhóm có kích thước nhất định


21

Các nhóm

Trong đại số trừu tượng, một nhóm là một tuple , trong đó là một tập hợp và là một hàm sao cho các hàm sau:G * G × G G(G,)GG×GG

  • Với mọi trong , .G ( x y ) z = x ( y z )x,y,zG(xy)z=x(yz)

  • Tồn tại một phần tử trong sao cho tất cả trong , .G x G x e = xeGxGx*e= =x

  • Với mỗi trong , tồn tại một phần tử trong sao cho .G y G x y = exGyGx*y= =e

Các trật tự của một nhóm được định nghĩa là số phần tử của .G(G,*)G

Đối với mỗi số nguyên dương nghiêm ngặt , tồn tại ít nhất một nhóm thứ tự . Ví dụ: là một nhóm như vậy, trong đó và .n ( C n , + n ) C n = { 0 , . . . , n - 1 } x + n y = ( x + y )nn(Cn,+n)Cn= ={0,...,n-1}x+ny= =(x+y)modn

Các nhóm đẳng hình

Đặt G: ={1,2} và xác định * theo x*y= =(x×y)mod3 . Khi đó 1*1= =1= =2*21*2= =2= =2*1 .

Tương tự, 0+20= =0= =1+210+21= =1= =1+20 .

Mặc dù các thành phần và hoạt động của các nhóm (G,*)(C2,+2) có tên khác nhau, các nhóm có chung cấu trúc.

Hai nhóm (G1,*1)(G2,*2) được cho là đẳng cấu nếu tồn tại một mệnh đề φ:G1G2 sao cho ϕ(x1y)=ϕ(x)2ϕ(y) với mọi x,y trong G1 .

Không phải tất cả các nhóm của cùng một thứ tự là đẳng cấu. Ví dụ: nhóm Klein là một nhóm thứ tự 4 không đồng hình với (C4,+4) .

Bài tập

Viết chương trình hoặc hàm chấp nhận số nguyên n không âm làm đầu vào và in hoặc trả về số lượng các nhóm không đẳng hình của thứ tự n .

Các trường hợp thử nghiệm

Input   Output
0       0
1       1
2       1
3       1
4       2
5       1
6       2
7       1
8       5
9       2
10      2
11      1
12      5
13      1
14      2
15      1
16      14
17      1
18      5
19      1
20      5

(lấy từ OEIS A000001 )

Quy tắc bổ sung

  • Không có giới hạn về thời gian thực hiện hoặc sử dụng bộ nhớ.

  • Các phần mềm xây dựng tầm thường hóa nhiệm vụ này, chẳng hạn như Mathicala FiniteGroupCount, không được phép.

  • Luật tiêu chuẩn được áp dụng.


14
Tất nhiên Mathicala có một nội dung cho việc này. : /
Alex A.

1
Trích dẫn Peter (từ một bình luận trên bài đăng về hộp cát của Evolution of OEIS ): "Nếu bạn xem các phần" công thức "và" chương trình ", ví dụ A000001 , A000003, A000019 thì câu trả lời không sử dụng nội dung chuyên dụng sẽ yêu cầu rất nhiều nghiên cứu. " (Nhấn mạnh mỏ.);)
Martin Ender

12
Một số người nói rằng không có Mathinica dựng sẵn không có, nhưng điều này vẫn còn phải nghiên cứu. Các huyền thoại khác nói rằng Mathicala tạo ra các nội dung bằng cách đọc tâm trí lập trình viên , nhưng điều này cũng chưa được xác nhận.
flawr

1
@flawr các monkeys_on_typewritersnội dung không có giấy tờ bao gồm tất cả mọi thứ không được bao phủ bởi các nội dung được ghi lại.
Cấp sông St

Tại sao (1 + 1)% 3 chứ không phải 2?
Cabbie407

Câu trả lời:


16

CJam, 189 187 byte

Điều này sẽ khó giải thích ... Sự phức tạp về thời gian được đảm bảo 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=},,}{!!}?

Nếu bạn đủ can đảm, hãy thử trực tuyến . Trên máy tính xách tay xảo quyệt của tôi, tôi có thể có tới 6 trình thông dịch Java hoặc 5 trong trình thông dịch trực tuyến.

Giải trình

Tôi không có nền tảng toán học lớn (vừa học xong trung học, bắt đầu CS vào tuần tới). Vì vậy, hãy chịu đựng nếu tôi phạm sai lầm, nói rõ ràng, hoặc làm mọi thứ theo cách không hiệu quả khủng khiếp.

Cách tiếp cận của tôi là một lực lượng vũ phu, mặc dù tôi đã cố gắng làm cho nó thông minh hơn một chút. Các bước chính là:

  1. Tạo ra tất cả các toán hạng có thể * cho một nhóm trật tự n (ví dụ, liệt kê tất cả các nhóm trật tự n );
  2. Tạo ra tất cả các bijections thể φ giữa hai nhóm về trật tự n ;
  3. Sử dụng kết quả từ bước 1 và 2, xác định tất cả các đẳng cấu giữa hai nhóm thứ tự n ;
  4. Sử dụng kết quả từ bước 3, đếm số lượng nhóm lên đến đẳng cấu.

Trước khi xem cách từng bước được thực hiện, hãy lấy một số mã tầm thường ra khỏi đường đi:

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)

Thuật toán sau không hoạt động chính xác với n <4 , các trường hợp từ 0 đến 3 được xử lý với phủ định kép.

Từ giờ trở đi, các phần tử của một nhóm sẽ được viết là {1, a, b, c, ...} , trong đó 1 là phần tử nhận dạng. Trong triển khai CJam, các phần tử tương ứng là {0, 1, 2, 3, ...} , trong đó 0 là phần tử nhận dạng.

Hãy bắt đầu từ bước 1. Viết tất cả các toán tử có thể cho một nhóm đơn hàng n tương đương với việc tạo tất cả các bảng Cayley n × n hợp lệ . Hàng và cột đầu tiên là tầm thường: cả hai đều là {1, a, b, c, ...} (từ trái sang phải, từ trên xuống).

      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

Biết rằng bảng Cayley cũng là một hình vuông Latin giảm (do thuộc tính hủy) cho phép tạo các bảng có thể theo từng hàng. Bắt đầu từ hàng thứ hai (chỉ mục 1), chúng tôi tạo ra tất cả các hoán vị duy nhất cho hàng đó, giữ cho cột đầu tiên cố định với giá trị của chỉ mục.

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

Tất nhiên, không phải tất cả các hoán vị đều hợp lệ: mỗi hàng và cột phải chứa tất cả các phần tử chính xác một lần. Một khối bộ lọc được sử dụng cho mục đích này (một giá trị trung thực giữ cho hoán vị, một khối giả sẽ loại bỏ nó):

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

Lưu ý rằng tôi đang lọc bên trong vòng lặp thế hệ: điều này làm cho mã dài hơn một chút (so với việc tạo và lọc riêng biệt), nhưng cải thiện hiệu năng rất nhiều. Số lượng hoán vị của một tập hợp kích thước nn! , vì vậy giải pháp ngắn hơn sẽ đòi hỏi nhiều bộ nhớ và thời gian.

Danh sách các bảng Cayley hợp lệ là một bước tuyệt vời để liệt kê các toán tử, nhưng là một cấu trúc 2D, nó không thể kiểm tra tính kết hợp, là một thuộc tính 3D. Vì vậy, bước tiếp theo là lọc ra các chức năng không liên kết.

{                                 }, 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]

Phù! Rất nhiều công việc, nhưng bây giờ chúng tôi đã liệt kê tất cả các nhóm thứ tự n (hoặc tốt hơn, các thao tác trên nó - nhưng tập hợp đã được sửa, vì vậy đó là điều tương tự). Bước tiếp theo: tìm đẳng cấu. Một đẳng cấu là một sự chọn lọc giữa hai trong số các nhóm đó sao cho φ (x ∗ y) = φ (x) ∗ (y) . Tạo ra những điều đó trong CJam là chuyện nhỏ: Ne!sẽ làm được. Làm thế nào chúng ta có thể kiểm tra chúng? Giải pháp của tôi bắt đầu từ hai bản sao của bảng Cayley cho x ∗ y . Trên một bản sao, φ được áp dụng cho tất cả các yếu tố, mà không cần chạm thứ tự của hàng hoặc cột. Điều này tạo ra bảng cho φ (x ∗ y) . Trên kia các yếu tố còn lại như họ đang có, nhưng các hàng và cột được ánh xạ qua φ . Đó là, hàng / cộtx trở thành hàng / cột φ (x) . Điều này tạo ra bảng cho φ (x) ∗ (y) . Bây giờ chúng ta có hai bảng, chúng ta chỉ cần so sánh chúng: nếu chúng giống nhau, chúng ta đã tìm thấy một đẳng cấu.

Tất nhiên, chúng ta cũng cần tạo các cặp nhóm để kiểm tra đẳng cấu trên. Chúng tôi cần tất cả sự kết hợp 2 của các nhóm. Có vẻ như CJam không có toán tử cho các kết hợp. Chúng ta có thể tạo chúng bằng cách lấy từng nhóm và chỉ kết hợp nó với các phần tử theo sau nó trong danh sách. Thực tế thú vị: số kết hợp 2 là n × (n - 1) / 2 , cũng là tổng của n - 1 số tự nhiên đầu tiên . Các số như vậy được gọi là số tam giác: thử thuật toán trên giấy, một hàng cho mỗi phần tử cố định và bạn sẽ thấy lý do tại sao.

: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

Đoạn mã trên sửa lỗi phần tử đầu tiên của cặp, L [X] và kết hợp nó với các nhóm khác (hãy gọi mỗi một trong số Y đó ). Nó chuyển cặp đến một khối kiểm tra đẳng cấu mà tôi sẽ hiển thị trong giây lát. Khối cung cấp cho trở lại một danh sách các giá trị của YL [X] là đẳng cấu với Y . Sau đó L [X] được thêm vào danh sách này. Trước khi hiểu lý do tại sao các danh sách được thiết lập theo cách như vậy, chúng ta hãy xem xét nghiệm đẳng cấu:

\_@                                      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

Tuyệt vời, bây giờ chúng tôi có một danh sách các bộ như [{L [0], Y1, Y2, ...}, {L [1], Y1, ...}, ...] . Ý tưởng ở đây là, bởi tính chất bắc cầu, nếu bất kỳ hai tập hợp nào có ít nhất một phần tử chung thì tất cả các nhóm trong hai bộ đều là đẳng cấu. Chúng có thể được tổng hợp thành một bộ duy nhất. Vì L [X] sẽ không bao giờ xuất hiện trong các kết hợp được tạo bởi L [X + ...] , sau khi tổng hợp, mỗi bộ đẳng cấu sẽ có một yếu tố duy nhất. Vì vậy, để có được số lượng đồng phân, đủ để đếm có bao nhiêu nhóm xuất hiện chính xác một lần trong tất cả các nhóm của các nhóm đẳng cấu. Để làm điều này, tôi mở khóa các tập hợp để chúng trông giống như [L [0], Y1, Y2, ..., L [1], Y1, ...] , sắp xếp danh sách để tạo các cụm của cùng một nhóm và cuối cùng RLE mã hóa nó.

:~            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

Đó là tất cả mọi người.


2
Đó là một trong những lời giải thích. Tốt đẹp.
The_Basset_Hound

1
@The_Basset_Hound ... aaaand hiện đã kết thúc;)
Andrea Biondo

Tôi coi câu trả lời của mình là không cạnh tranh, vì vậy tôi đã chấp nhận câu trả lời này.
Dennis

4

CJam, 73 byte

0ri:Re!Rm*{:Tz0=R,=[R,Te_]m!{~ff{T==}e_}/=&},{:T,e!{:PPff{T==P#}}%$}%Q|,+

Độ phức tạp thời gian của mã trên kém hơn O (n! N ) .

Đầu vào n = 4 đã có nhiều cho trình thông dịch trực tuyến .

Sử dụng trình thông dịch Java , đầu vào n = 5 có thể có thể, nếu bạn có đủ RAM và kiên nhẫn.

Tìm nhóm

Cho một nhóm (G, ∗) của thứ tự n , chúng ta có thể chọn một mệnh đề tùy ý φ: G -> C n sao cho φ (e) = 0 .

φ sẽ trở thành một đẳng cấu của (G, *)(C n , * ') nếu chúng ta định nghĩa *' bởi x *' y = φ (φ -1 (x) * φ -1 (y)) .

Điều này có nghĩa là nó đủ để nghiên cứu tất cả các toán tử nhóm trong C n sao cho 0 là phần tử trung tính.

Chúng ta sẽ biểu diễn một toán tử nhóm trong C n bằng một mảng hình chữ nhật T có kích thước n × n sao cho T [x] [y] = x ∗ y .

Để tạo ra một mảng như vậy, chúng ta có thể bắt đầu bằng cách chọn một hoán vị C n cho mỗi hàng n của nó .

Bằng cách này, 0 sẽ có mặt trong tất cả các hàng (nhưng không nhất thiết là tất cả các cột ), có nghĩa là điều kiện thứ ba (tồn tại của một nghịch đảo) sẽ được đáp ứng, bất kể e có thể là gì.

Chúng ta có thể sửa e = 0 bằng cách yêu cầu cột đầu tiên của T bằng C n . Cụ thể, điều kiện thứ hai (sự tồn tại của một yếu tố trung tính) sẽ được giữ vững.

Để xác minh rằng T tương ứng với một toán tử nhóm, tất cả những gì còn lại phải làm là xác minh rằng điều kiện đầu tiên (tính kết hợp) giữ. Điều này có thể được thực hiện một cách triệt để bằng cách kiểm tra T [T [x] [y]] [z] == T [x] [T [y] [z]] cho tất cả x, y, z trong C n .

Đếm các nhóm không đẳng hình

Phương pháp trên để tìm các nhóm sẽ mang lại một số nhóm đẳng hình. Thay vì xác định những cái nào là đẳng cấu, chúng ta tạo ra họ của tất cả các nhóm đẳng cấu cho mỗi nhóm.

Điều này có thể đạt được bằng cách lặp lại trên tất cả các mệnh đề : C n -> C n và xác định mảng liên quan , được xác định bởi Tφ [x] [y] = φ -1 (T [φ (x)] [φ (y )]) .

Tất cả những gì còn lại phải làm là đếm số lượng các gia đình riêng biệt.

Mã làm gì

0         e# Push 0. For input 0, the remaining code will crash, leaving
          e# this 0 on the stack.
ri:R      e# Read an integer from STDIN and save it in R.
e!        e# Push all permutations of [0 ... R-1].
Rm*       e# Push all arrays of 6 permutations of [0 ... R-1].
{         e# Filter; for each array:
  :T      e#   Save it in T.
  z0=R,=  e#   Check if the first column equals [0 ... R-1].
  [R,Te_] e#   Push [0 ... R-1] and a flattened T.
  m!{     e#   For both pairs (any order):
    ~     e#     Unwrap the pair.
    ff{   e#     For each X in the first: For each Y in the second:
      T== e#       Push T[X][Y].
    }     e#
  }/      e#
  =       e#   Check for equality, i.e., associativity.
  &       e#   Bitwise AND with the previous Boolean
},        e# Keep T iff the result was truthy.
{         e# For each kept array:
  :T      e#   Save it in T
  ,e!     e#   Push all permutations of [0 ... R-1].
  {       e#   For each permutation:
    :PP   e#     Save it in P. Push a copy.
    ff{   e#     For each X in P: For each Y in P:
      T== e#       Push T[X][Y].
      P#  e#       Find its index in P.
    }     e#
  }%      e#
  $       e#   Sort the results.
}%        e#
Q|,       e# Deduplicate and count.
+         e# Add the result to the 0 on the stack.

Tốt đẹp. Tôi đã thử một vũ phu "ngu ngốc", nhưng rất khó để lên 5, vì vậy tôi đã giao dịch byte cho tốc độ.
Andrea Biondo

1

Python 2 , 515 507 byte

  • Đã lưu tám byte nhờ Dennis .
def F(n):
 def f(k,*s):n==len(set(s))and S.add(s);{k and f(~-k,j,*s)for j in I}
 def c(k,*G):k and{s in G or c(~-k,s,*G)for s in S}or(I in G)&all((o(x,y)in G)&any(I==o(z,x)for z in G)for x in G for y in G)and A.add(G)
 S=set();A=S-S;I=tuple(range(n));o=lambda x,y:tuple(y[x[j]]for j in I);i=lambda G,H:any(all(o(H[B[i]],H[B[j]])==H[B[[k for k in I if G[k]==o(G[i],G[j])][0]]]for i in I for j in I)for B in S);f(n);c(n);K=list(A);[G in K and{G!=H and i(G,H)and K.remove(H)for H in K}for G in A];return len(K)

Hãy thử trực tuyến!


n Σnn

Liên kết đến phiên bản dài dòng .


Làm các đơn đặt hàng svà quan Gtrọng? Nếu không, bạn có thể sử dụng def f(k,*s):...f(~-k,j,*s)...def c(k,*G):...c(~-k,s,*G).....
Dennis

@Dennis Họ không; cảm ơn.
Jonathan Frech
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.