Calcola il simbolo Kronecker


9

Rilevanti collegamenti qui e qui , ma ecco la versione breve:

Hai un input di due numeri interi ae btra infinito negativo e infinito (anche se se necessario, posso limitare l'intervallo, ma la funzione deve comunque accettare input negativi).

Definizione del simbolo di Kronecker

È necessario restituire il simbolo Kronecker (a|b)per gli input ae bdove

(a|b) = (a|p_1)^e_1 * (a|p_2)^e_2 * ... * (a|p_n)^e_n

dove b = p_1^e_1 * p_2^e_2 * ... * p_n^e_n, ed p_ie e_isono i numeri primi e gli esponenti nella fattorizzazione primaria di b.

Per uno strano numero primo p, (a|p)=a^((p-1)/2) (mod p)come definito qui .

Per b == 2,(n|2)={0 for n even; 1 for n odd, n=+/-1 (mod 8); -1 for n odd, n=+/-3 (mod 8)

Per b == -1,(n|-1)={-1 for n<0; 1 for n>0

Se a >= b, (a|b) == (z|b)dove z == a % b. Con questa proprietà, e come spiegato qui e qui , ac'è un residuo quadratico di bif z, anche se a >= b.

(-1|b)= 1se b == 0,1,2 (mod 4)e -1se b == 3 (mod 4). (0|b)è 0tranne (0|1)che è 1, perché (a|1)è sempre 1e per negativo a, (-a|b) == (-1|b) * (a|b).

L'output del simbolo Kronecker è sempre -1, 0 or 1, dove l'output è 0se ae bha dei fattori comuni. If bè un numero primo dispari, (a|b) == 1if aè un mod di residuo quadraticob e -1se non lo è non è un residuo quadratico.

Regole

  • Il tuo codice deve essere un programma o una funzione.

  • Gli ingressi devono essere nell'ordine a b.

  • L'output deve essere o -1, 0o 1.

  • Questo è il golf del codice, quindi il tuo codice non deve essere efficiente, solo breve.

  • Nessun built-in che calcola direttamente il Kronecker oi relativi simboli Jacobi e Legendre. Altri built-in (ad esempio per la scomposizione in fattori primi) sono fair game.

Esempi

>>> kronecker(1, 5)
1
>>> kronecker(3, 8)
-1
>>> kronecker(15, 22)
1
>>> kronecker(21, 7)
0
>>> kronecker(5, 31)
1
>>> kronecker(31, 5)
1
>>> kronecker(7, 19)
1
>>> kronecker(19, 7)
-1
>>> kronecker(323, 455625)
1
>>> kronecker(0, 12)
0
>>> kronecker(0, 1)
1
>>> kronecker(12, 0)
0
>>> kronecker(1, 0)
1
>>> kronecker(-1, 5)
1
>>> kronecker(1, -5)
1
>>> kronecker(-1, -5)
-1
>>> kronecker(6, 7)
-1
>>> kronecker(-1, -7)
1
>>> kronecker(-6, -7)
-1

Questa è una funzione complicata, quindi per favore fatemi sapere se qualcosa non è chiaro.


Sei sicuro di non voler disabilitare i built-in? reference.wolfram.com/language/ref/KroneckerSymbol.html
Martin Ender

@ MartinBüttner Stavo modificando in esempi quando ho visto il tuo commento. Non consentirò incorporamenti che calcolano direttamente i simboli Kronecker, Jacobi o Legendre, ma qualsiasi altra cosa (comprese le funzioni di fattorizzazione primaria) dovrebbe essere un gioco equo.
Sherlock9,

non sono del tutto sicuro del perché (31 | 5) dia 1. Non dovrebbe esserci un residuo qudratico, quindi perché non è -1?
Eumel,

anche il 7/19 dovrebbe essere 1 e il 19/7 dovrebbe essere -1 secondo la wiki che hai collegato
Eumel

3
Se le soluzioni devono gestire correttamente input negativi e zero, è necessario aggiungere alcuni casi di test a tale scopo.
Martin Ender,

Risposte:


2

CJam (70 byte)

{_g\zmf+f{:P2+"W>2*(
z1=
;1
7&4-z[0W0X0]=
P%P+P(2/#P%_1>P*-"N/<W=~}:*}

Demo online (casi di test generati con Mathematica).

Dissezione

{               e# Anonymous function. Stack: a b
  _g\zmf+       e# Factorise b, with special treatment for negatives
                e# CJam also gives special treatment to 0 and 1
                e# Stack: e.g. a [-1 2 2 5]; or a [-1 1]; or a [0 0]; or a [1 2 2 5]
  f{            e# For each "prime" factor P, find (a|P)
    :P2+        e# Extract code for P from an array formed by splitting a string
    "W>2*(      e#   a -> (a|-1)
z1=             e#   a -> (a|0)
;1              e#   a -> (a|1)
7&4-z[0W0X0]=   e#   a -> (a|2)
P%P+P(2/#P%_1>P*-" e# a -> (a|P) for odd prime P
    N/<W=~      e# Split string and select appropriate element
  }
  :*            e# Multiply the components together
}

Ho trovato diversi modi (a|2)per valutare lo stesso numero di caratteri e ho scelto di usare quello con la presentazione più chiara.

integer array <W= l'IMO è un modo abbastanza elegante di eseguire fallback: se l'intero è maggiore della lunghezza dell'array, selezioniamo l'ultimo elemento.

Altri commenti

È deludente che per lo strano primo plo stile diretto di Fermat (a|p)sia così breve, perché c'è un modo molto golfy di trovare uno (a|n)strano positivo nche volevo usare. La base è il lemma di Zolotarev:

Se pè un numero primo dispari ed aè un coprimi intero per pallora il simbolo Legendre (a|p)è il segno della permutazionex -> ax (mod p)

Ciò è stato rafforzato da Frobenius

Se ae bsono interi dispari positivi coprimi allora il simbolo Jacobi (a|b)è il segno della permutazionex -> ax (mod b)

e da Lerch a

Se bè un numero intero dispari positivo ed aè un numero intero intero, ballora il simbolo Jacobi (a|b)è il segno della permutazionex -> ax (mod b)

Vedi Brunyate e Clark, estendere l'approccio Zolotarev-Frobenius alla reciprocità quadratica , The Ramanujan Journal 37.1 (2014): 25-50 per riferimenti.

E può essere facilmente rafforzato un ulteriore passo avanti (anche se non l'ho visto in letteratura) a

Se bè un numero intero dispari positivo ed aè un numero intero, allora il simbolo Jacobi (a|b)è il simbolo Levi-Civita della mappa x -> ax (mod b).

Prova: se aè coprime per ballora usiamo Zolotarev-Frobenius-Lerch; altrimenti la mappa non è una permutazione e il simbolo Levi-Civita è 0come desiderato.

Questo dà il calcolo del simbolo Jacobi

{_2m*{~>},@ff*\ff%::-:*g}

Ma il trattamento speciale richiesto (a|-1)e (a|2)significa che non ho trovato un modo per calcolare il simbolo di Kronecker che è più breve con questo approccio: è più breve di fattorizzare e trattare i numeri primi individualmente.


4

Python 3, 747 369 335 byte

Ad esempio una risposta, solo leggermente giocata a golf, e per darti un'idea di come sarà una risposta.

E sì, i fattori di scomposizione in fattori primi e di codifica della lunghezza di esecuzione sono paralizzati da Pyth con scuse a isaacg .

from itertools import*
def k(d,r):
 if d<0:a=-d;m=1
 else:a=d;m=0
 if r==1:return 1
 p=1;w=r;n=2;f=[]
 while n*n<=w:
  while w%n<1:w//=n;f+=n,
  n+=1
 if w>1:f+=w,
 z=[[k,len(list(g))]for k,g in groupby(f)]
 for i,j in z:
  if i==2:p*=pow(-1,(a*a-1)//8)
  x=pow(a,(i-1)//2,i)
  if x>1:x-=i
  p*=x**j
 if m:p*=pow(-1,(r-1)//2)
 return p

4
Scuse accettate - Sono contento che qualcuno legga il codice sorgente di Pyth.
isaacg,

2

Mathematica, 169 175 165 byte

(1|-1)~k~0=_~k~1=1
_~k~0=0
a_~k~-1=If[a<0,-1,1]
a_~k~2=DirichletCharacter[8,2,a]
a_~k~p_/;PrimeQ@p=Mod[a^((p-1)/2),p,-1]
a_~k~b_:=1##&@@(a~k~#^#2&@@@FactorInteger@b)

2

LabVIEW, 44 byte LabVIEW Primitives

Dato che è simmetrico, ho scambiato gli input se a era più grande di b.

Rappresenta ora la vera formula

contando come sempre secondo

per caso vero


Sfortunatamente, (a|b) != (b|a)in tutti i casi. Nella maggior parte dei casi sì, ma non in tutti. Sebbene funzionerebbe se riducessi a mod binvece di scambiarli.
Sherlock9,

dato che ora ho la spiegazione posso modificarla, dammi un minuto
Eumel

1
C'è un modo per testarlo? Non capisco davvero come funziona LabView.
Sherlock9,

questa è una buona domanda, posso pensare a 2 modi. Per prima cosa posso creare un file .exe e inviarlo a te, in secondo luogo puoi ottenere una versione di prova labview e posso inviarti il ​​vi o puoi ricostruirlo dalla foto.
Eumel

7
Non si tratta di 44 byte. Se si definisce un sistema di punteggio non basato sulla dimensione del file, è necessario chiamarlo in modo diverso dai byte.
febbraio

1

Julia, 195 byte

k(a,b)=b==0?a∈[1,-1]?1:0:b==1?1:b==2?iseven(a)?0:a%8∈[1,-1]?1:-1:b==-1?a<1?-1:1:isprime(b)&&b>2?a%b==0?0:a∈[i^2%b for i=0:b-1]?1:-1:k(a,sign(b))*prod(i->k(a,i)^factor(b)[i],keys(factor(b)))

Questa è una funzione ricorsiva kche accetta due numeri interi e restituisce un numero intero.

Ungolfed:

function k(a::Integer, b::Integer)
    if b == 0
        return a  [1, -1] ? 1 : 0
    elseif b == 1
        return 1
    elseif b == 2
        return iseven(a) ? 0 : a % 8  [1, -1] ? 1 : -1
    elseif b == -1
        return a < 1 ? -1 : 1
    elseif isprime(b) && b > 2
        return a % b == 0 ? 0 : a  [i^2 % b for i = 1:b-1] ? 1 : -1
    else
        p = factor(b)
        return k(a, sign(b)) * prod(i -> k(a, i)^p[i], keys(p))
    end
end

1

Haskell, 286 byte

a#0|abs a==1=1|1<2=0
a#1=1
a#2|even a=0|mod a 8`elem`[1,7]=1|1<2=(-1)
a#b|b<0=a`div`abs a*a#(-b)|all((/=0).mod b)[2..b-1]=if elem n[0,1] then n else(-1)|1<2=product$map(a#)$f b where n=a^(div(b-1)2)`mod`b
f 1=[]
f n|n<0=(-1):f(-n)|1<2=let p=head$filter((==0).mod n)[2..n]in p:f(div n p)

Probabilmente non completamente ottimizzato, ma uno sforzo valoroso. Il simbolo Kronecker è definito come la funzione di infissione a # b, cioè

*Main>323#455265 
1
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.