Conteggio di gruppi abeliani di una determinata dimensione


14

sfondo

L'ultima volta, abbiamo contato gruppi di una determinata dimensione , il che è un problema non banale.

Questa volta, conteremo solo i gruppi abeliani , cioè i gruppi con un'operazione commutativa. Formalmente, un gruppo (G, *) è abeliano se x * y = y * x per per tutti x, y in G .

Il problema diventa molto più semplice in questo modo, quindi li conteremo in modo efficiente.

Compito

Scrivi un programma o una funzione che accetta un numero intero non negativo n come input e stampa o restituisce il numero di gruppi abeliani non isomorfi dell'ordine n .

Un modo per calcolare il numero di gruppi - che indicheremo con A (n) - è osservando quanto segue:

  • A (0) = 0

  • Se p è un numero primo, A (p k ) è uguale al numero di partizioni intere di k . (cfr. OEIS A000041 )

  • Se n = mk e m e k sono co-primi, A (n) = A (m) A (k) .

È possibile utilizzare questo o qualsiasi altro metodo di calcolo di A (n) .

Casi test

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

(tratto da OEIS A000688 )

Regole aggiuntive

  • Dato abbastanza tempo, RAM e una dimensione del registro che può contenere l'input, il tuo codice dovrebbe funzionare (in teoria) per interi arbitrariamente grandi.

  • Il codice deve funzionare per tutti i numeri interi compresi tra 0 e 2 63 - 1 e terminare in meno di 10 minuti sulla mia macchina (Intel i7-3770, 16 GiB RAM, Fedora 21).

    Prima di inviare la risposta, assicurati di impostare il tempo per il codice per gli ultimi tre casi di test.

  • Gli incorporamenti che banalizzano questo compito, come quello di Mathematica FiniteAbelianGroupCount, non sono ammessi.

  • Non sono consentiti incorporati che restituiscono o contano le partizioni intere di un numero o le partizioni di un elenco.

  • Si applicano le regole standard del .


Il sistema di fattorizzazione principale di Pyth è troppo lento per questa sfida: devo risolverlo.
isaacg,

Risposte:


3

CJam ( 39 38 byte)

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

Demo online

Questo segue la linea suggerita di trovare una scomposizione in fattori primi ( mF) e quindi calcolare le partizioni di ciascun potere e prendere il loro prodotto.

Esistono due casi speciali per mF: fattori 0come 0^1e 1come 1^1. Quest'ultimo non richiede un trattamento speciale: esiste un gruppo abeliano di dimensione 1 e una partizione di 1. Tuttavia, zero richiede un caso speciale.

Il conteggio delle partizioni utilizza una ricorrenza per A008284(n, k)il numero di partizioni nin kparti. In OEIS è indicato come

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

ma penso che sia più utile pensare alla somma che va da 1a min(k, n-k).

Dissezione

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

5

CJam, 50 49 47 43 byte

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

Utilizza la mFfattorizzazione integrata di CJam e una porta memorizzata di questa funzione del numero di partizione Python:

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

o non golfato:

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)

Come la risposta di @RetoKoradi, l'ultimo caso richiede circa 17 secondi sull'interprete offline perché è il tempo impiegato da CJam per fattorizzare il numero. Quindi l'ho lasciato fuori da questa suite di test online .

Spiegazione completa

[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

4

Mathematica, 96 94 88 byte

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

Non sono così abile con Mathematica, ma ho pensato di provarlo. Grazie a @ MartinBüttner per -6 byte.

Questo utilizza la formula della funzione di generazione per le partizioni intere.


3

CJam, 58 byte

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

Provalo online

L'ultimo esempio di test impiega un'eternità (o almeno più di quanto volessi aspettare) nell'interprete online, ma termina in 17 secondi con la versione offline di CJam sul mio laptop. Tutti gli altri esempi di test sono praticamente istantanei.

Questo utilizza l' mFoperatore CJam , che fornisce la scomposizione in fattori primi con esponenti. Il risultato è quindi il prodotto della partizione conta per ogni esponente.

La parte principale del codice sta calcolando i conteggi delle partizioni. Ho implementato l'algoritmo ricorsivo sulla pagina di Wikipedia , usando l' joperatore che supporta la ricorsione con la memoizzazione.

Spiegazione:

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.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.