Menghitung kelompok Abelian dengan ukuran tertentu

14

Latar Belakang

Terakhir kali, kami menghitung kelompok dengan ukuran tertentu , yang merupakan masalah non-sepele.

Kali ini, kami hanya akan menghitung grup Abelian , yaitu grup dengan operasi komutatif. Secara formal, kelompok (G, *) adalah Abelian jika x * y = y * x untuk semua x, y di G .

Masalahnya menjadi lebih sederhana dengan cara ini, jadi kita akan menghitungnya secara efisien.

Tugas

Tulis program atau fungsi yang menerima bilangan bulat non-negatif n sebagai input dan mencetak atau mengembalikan jumlah kelompok Abelian non-isomorfik orde n .

Salah satu cara menghitung jumlah grup - yang akan kami tunjukkan dengan A (n) - adalah dengan mengamati yang berikut:

  • A (0) = 0

  • Jika p adalah bilangan prima, A (p k ) sama dengan jumlah partisi integer k . ( cfr . OEIS A000041 )

  • Jika n = mk , dan m dan k adalah co-prime, A (n) = A (m) A (k) .

Anda dapat menggunakan ini atau metode penghitungan A (n) lainnya .

Uji kasus

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

(diambil dari OEIS A000688 )

Aturan tambahan

  • Diberi cukup waktu, RAM dan ukuran register yang dapat menampung input, kode Anda harus bekerja (secara teori) untuk bilangan bulat besar yang sewenang-wenang.

  • Kode Anda harus bekerja untuk semua bilangan bulat antara 0 dan 2 63 - 1 dan selesai di bawah 10 menit pada komputer saya (Intel i7-3770, 16 GiB RAM, Fedora 21).

    Pastikan Anda menghitung waktu kode Anda untuk tiga kasus pengujian terakhir sebelum mengirimkan jawaban Anda.

  • Built-in yang meremehkan tugas ini, seperti Mathematica FiniteAbelianGroupCount, tidak diperbolehkan.

  • Built-in yang mengembalikan atau menghitung partisi integer angka atau partisi daftar tidak diperbolehkan.

  • Aturan standar berlaku.

Dennis
sumber
Sistem faktorisasi utama Pyth terlalu lambat untuk tantangan ini - saya harus memperbaikinya.
isaacg

Jawaban:

3

CJam ( 39 38 bytes)

qimF{~M\{_ee{~\)<1b}%1+a\+}*0=1be&}%:*

Demo online

Ini mengikuti garis yang disarankan untuk menemukan factorisation utama ( mF) dan kemudian menghitung partisi masing-masing kekuatan dan mengambil produk mereka.

Ada dua kasus khusus untuk mF: itu faktor 0as 0^1dan 1as 1^1. Yang terakhir tidak memerlukan perlakuan khusus: ada satu kelompok Abelian ukuran 1, dan satu partisi 1. Namun, nol memang membutuhkan kasing khusus.

Penghitungan partisi menggunakan pengulangan untuk A008284(n, k), jumlah partisi nmenjadi kbeberapa bagian. Dalam OEIS diberikan sebagai

T(n, k) = Sum_{i=1..k} T(n-k, i), for 1<=k<=n-1; T(n, n) = 1 for n >= 1.

tapi saya pikir lebih bermanfaat untuk memikirkan jumlah yang berkisar dari 1hingga min(k, n-k).

Pembedahan

q~              e# Parse input into an integer
mF              e# Factorise it
{               e# For each factor p^a
  ~             e#   Split the array [p a]
                e#   The following lines count partitions of a
                e#   (Note: they would be buggy if a were ever 0, but it isn't)
  M\{           e#   Starting with a table of zero rows, repeat a times
    _ee         e#     Copy table and pair each row with its index
    {~\)<1b}%   e#     Extract that prepended index and use it to sum for each j
                e#     the first jth items of row j
    1+          e#     Append a 1 for P(i, i)
    a\+         e#     Prepend the new row to the table (which is stored in reverse)
  }*
  0=1b          e#   Sum the elements in the latest (first) row

  e&            e#   If p was 0 then replace with 0
}%
:*              e# Take the product
Peter Taylor
sumber
5

CJam, 50 49 47 43 byte

ri_mF{1=_L{1$0>{,f{):X-Xj}:+}{;!}?}2j}%:*e&

Menggunakan mFfactorisation bawaan CJam dan port memoised dari fungsi nomor partisi Python ini:

p=lambda n,x:n==0 or n>0and sum(p(n+~a,a+1)for a in range(x))

atau ungolfed:

def p(n, x): # Call like p(n, n). n is number remaining, x is max part size
  if n > 0:
    return sum(p(n-a-1,a+1)for a in range(x))
  else:
    return (n==0)

Seperti jawaban @ RetoKoradi, kasus terakhir membutuhkan sekitar 17 detik pada penerjemah offline karena itulah berapa lama yang diperlukan CJam untuk memfaktorkan angka tersebut. Oleh karena itu saya telah meninggalkannya dari test suite online ini .

Penjelasan lengkap

[Main body]
ri                                Read input and convert to int
  _          e&                   Logical AND input with final result to special case 0 
   mF                             Factorise input into [base, exponent] pairs
     {...}%                       Map, converting each pair to a partition number
           :*                     Take product

[Pair -> partition]
1=_                               Get exponent and copy (n,x in above Python)
   L                              Initialise empty cache
    {                       }2j   Memoise with 2 arguments
     1$0>                         Check if n > 0
         {            }{  }?      Execute first block if yes, else second block
                        ;!        Return (n == 0)
          ,f{      }              For each a in range(x) ...
             ):X-Xj               Call p(n-a-1,a+1) recursively
                    :+            Sum the results
Sp3000
sumber
4

Mathematica, 96 94 88 byte

f=1##&@@#&;f[SeriesCoefficient[1/f[1-x^Range@#],{x,0,#}]&/@Last/@FactorInteger@#]Sign@#&

Saya tidak begitu mahir dengan Mathematica, tapi saya pikir saya akan mencobanya. Terima kasih kepada @ MartinBüttner untuk -6 byte.

Ini menggunakan rumus fungsi pembangkit untuk partisi integer.

Sp3000
sumber
3

CJam, 58 byte

li_mF{1=_L{_1>{_2$<{\;_j}{\,f{)_@\-j}:+}?}{;;1}?}2j}%:*\g*

Cobalah online

Contoh pengujian terakhir membutuhkan waktu lama (atau setidaknya lebih lama dari yang saya mau tunggu) di penerjemah online, tetapi selesai dalam 17 detik dengan versi offline CJam di laptop saya. Semua contoh uji lainnya cukup instan.

Ini menggunakan mFoperator CJam , yang memberikan faktorisasi utama dengan eksponen. Hasilnya kemudian produk dari partisi dihitung untuk setiap eksponen.

Bagian utama dari kode adalah menghitung jumlah partisi. Saya menerapkan algoritma rekursif pada halaman wikipedia , menggunakan joperator yang mendukung rekursi dengan memoisasi.

Penjelasan:

li    Get input and convert to int.
_     Make a copy to handle 0 special case at the end.
mF    Factorization with exponents.
{     Loop over factors.
  1=    Take exponent from [factor exponent] pair.
  _     Repeat it, recursive calls are initiated with p(n, n).
  L     Empty list as start point of memoization state.
  {     Start recursive block. Argument order is (m, n), opposite of Wikipedia.
    _1>   Check for n > 1.
    {     Start n > 1 case.
      _2$   Copy both m and n.
      <     Check for n < m.
      {     n < m case.
        \;    Pop m.
        _     Copy n.
        j     Make the p(n, n) recursive call.
      }     End n < m case.
      {     Main part of algorithm that makes recursive calls in loop.
        \,    Generate [0 1 ... m-1] range for k.
        f{    Start loop over k.
          )     Increment, since k goes from 1 to m.
          _     Copy k.
          @\    Rotate n to top, and swap. Now have k n k at top of stack.
          -     Subtract, now have k n-k at top of stack.
          j     Make the p(n-k, k) recursive call.
        }     End loop over k.
        :+    Sum up all the values.
      }?    Ternaray operator for n < m condition.
    }     End n > 1 case.
    {     n <= 1 case.
      ;;1   Pop m, n values, and produce 1 as result.
    }?    Ternary operator for n > 1 condition.
  }2j   Recursive call with memoization, using 2 values.
}%    End loop over factors.
:*    Multiply all values.
\     Swap original input to top.
g     Signum.
*     Multiply to get 0 output for 0 input.
Reto Koradi
sumber