Calculez le symbole Kronecker

9

Liens pertinents ici et ici , mais voici la version courte:

Vous avez une entrée de deux entiers aet bentre l'infini négatif et l'infini (bien que si nécessaire, je peux restreindre la plage, mais la fonction doit toujours accepter les entrées négatives).

Définition du symbole Kronecker

Vous devez renvoyer le symbole Kronecker (a|b)pour les entrées aet b

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

b = p_1^e_1 * p_2^e_2 * ... * p_n^e_n, et p_iet e_isont les nombres premiers et exposants dans la décomposition en facteurs premiers de b.

Pour un nombre impair p, (a|p)=a^((p-1)/2) (mod p)tel que défini ici .

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

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

Si a >= b, (a|b) == (z|b)z == a % b. Par cette propriété, et comme expliqué ici et ici , aest un résidu quadratique de bsi zest, même si a >= b.

(-1|b)= 1si b == 0,1,2 (mod 4)et -1si b == 3 (mod 4). (0|b)est , 0sauf pour ce (0|1)qui est 1, parce (a|1)est toujours 1et négative a, (-a|b) == (-1|b) * (a|b).

La sortie du symbole Kronecker est toujours -1, 0 or 1, où la sortie est 0si aet bont des facteurs communs. Si best un premier impair, (a|b) == 1si aest un mod de résidu quadratiqueb , et -1si ce n'est pas un résidu quadratique.

Règles

  • Votre code doit être un programme ou une fonction.

  • Les entrées doivent être dans l'ordre a b.

  • La sortie doit être soit -1, 0soit 1.

  • Il s'agit de code golf, donc votre code n'a pas besoin d'être efficace, juste court.

  • Aucune fonction intégrée qui calcule directement le Kronecker ou les symboles Jacobi et Legendre associés. Les autres fonctions intégrées (pour la factorisation principale, par exemple) sont équitables.

Exemples

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

C'est une fonction compliquée, alors faites-moi savoir si quelque chose n'est pas clair.

Sherlock9
la source
Voulez-vous vraiment ne pas interdire les fonctions intégrées? reference.wolfram.com/language/ref/KroneckerSymbol.html
Martin Ender
@ MartinBüttner J'étais en train de modifier des exemples quand j'ai vu votre commentaire. Je n'accepterai pas les éléments intégrés qui calculent directement les symboles Kronecker, Jacobi ou Legendre, mais tout le reste (y compris les fonctions de factorisation principale) devrait être un jeu équitable.
Sherlock9
Je ne sais pas vraiment pourquoi (31 | 5) donne 1. Il ne devrait pas y avoir de résidu qudratique, alors pourquoi n'est-il pas -1?
Eumel
7/19 devrait également être 1 et 19/7 devrait être -1 selon le wiki que vous avez lié
Eumel
3
Si les solutions doivent gérer correctement les entrées négatives et nulles, vous devez absolument ajouter des cas de test pour cela.
Martin Ender

Réponses:

2

CJam (70 octets)

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

Démo en ligne (cas de test générés avec Mathematica).

Dissection

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

J'ai trouvé plusieurs façons d'évaluer (a|2)le même nombre de caractères, et j'ai choisi d'utiliser celui avec la présentation la plus claire.

integer array <W= est IMO une façon assez élégante de faire des replis: si l'entier est supérieur à la longueur du tableau, nous sélectionnons le dernier élément.

Autres commentaires

Il est décevant que pour le premier impair, ple style direct de Fermat (a|p)soit si court, car il y a une façon très golfique de trouver (a|n)un impair positif nque je voulais utiliser. La base est le lemme de Zolotarev:

Si pest un nombre premier impair et aest un nombre entier premier palors le symbole de Legendre (a|p)est le signe de la permutationx -> ax (mod p)

Cela a été renforcé par Frobenius pour

Si aet bsont des entiers impairs positifs premiers entre eux, alors le symbole Jacobi (a|b)est le signe de la permutationx -> ax (mod b)

et par Lerch à

Si best un entier impair positif et aest un nombre entier inférieur à balors le symbole Jacobi (a|b)est le signe de la permutationx -> ax (mod b)

Voir Brunyate et Clark, Extending the Zolotarev-Frobenius approach to quadratic reciprocity , The Ramanujan Journal 37.1 (2014): 25-50 pour les références.

Et il peut facilement être renforcé un peu plus loin (même si je n'ai pas vu cela dans la littérature) pour

Si best un entier impair positif et aest un entier, alors le symbole Jacobi (a|b)est le symbole Levi-Civita de la carte x -> ax (mod b).

Preuve: si aest coprime à balors on utilise Zolotarev-Frobenius-Lerch; sinon, la carte n'est pas une permutation et le symbole Levi-Civita est 0comme souhaité.

Cela donne le calcul du symbole Jacobi

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

Mais le traitement spécial requis (a|-1)et (a|2)signifie que je n'ai pas trouvé de moyen de calculer le symbole Kronecker qui est plus court avec cette approche: il est plus court de factoriser et de traiter les nombres premiers individuellement.

Peter Taylor
la source
4

Python 3, 747 369 335 octets

À titre d'exemple de réponse, seulement légèrement joué au golf, et pour vous donner une idée de ce à quoi ressemblera une réponse.

Et oui, la factorisation principale et les bits d'encodage de la longueur d'exécution sont importés de Pyth avec des excuses à 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
Sherlock9
la source
4
Excuses acceptées - je suis content que quelqu'un lise le code source Pyth.
isaacg
2

Mathematica, 169 175 165 octets

(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)
alephalpha
la source
2

LabVIEW, 44 octets Primitives LabVIEW

Puisque son i symétrique a échangé les entrées si a était plus grand que b.

Représente la vraie formule maintenant

compter comme toujours selon

pour vrai cas

Eumel
la source
Malheureusement, (a|b) != (b|a)dans tous les cas. Dans la plupart des cas, oui, mais pas dans tous. Bien que cela fonctionnerait si vous réduisiez a mod bau lieu de les échanger.
Sherlock9
puisque j'ai l'explantion maintenant je peux le modifier, donnez-moi un min
Eumel
1
Existe-t-il un moyen de tester cela? Je ne comprends pas vraiment comment fonctionne LabView.
Sherlock9
c'est une bonne question, je peux penser à 2 façons. D'abord je peux construire un .exe et vous l'envoyer, deuxièmement vous pouvez obtenir une version de test labview et je peux vous envoyer le vi ou vous pouvez le reconstruire à partir de la photo.
Eumel
7
Ce n'est pas 44 octets. Si vous définissez un système de notation qui n'est pas basé sur la taille du fichier, vous devez l'appeler autre chose que des octets.
feersum
1

Julia, 195 octets

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)))

Il s'agit d'une fonction récursive kqui accepte deux entiers et renvoie un entier.

Non golfé:

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
Alex A.
la source
1

Haskell, 286 octets

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)

Probablement pas complètement optimisé, mais un vaillant effort. Le symbole Kronecker est défini comme la fonction infixe a # b, c'est-à-dire

*Main>323#455265 
1
killmous
la source