Calcular o símbolo Kronecker

9

Links relevantes aqui e aqui , mas aqui está a versão curta:

Você tem uma entrada de dois números inteiros ae bentre infinito negativo e infinito (embora, se necessário, eu possa restringir o intervalo, mas a função ainda deve aceitar entradas negativas).

Definição do símbolo Kronecker

Você deve retornar o símbolo Kronecker (a|b)para entradas ae bonde

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

onde b = p_1^e_1 * p_2^e_2 * ... * p_n^e_n, e p_ie e_isão os primos e expoentes na fatoração primária de b.

Para um primo ímpar p, (a|p)=a^((p-1)/2) (mod p)conforme definido aqui .

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

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

Se a >= b, (a|b) == (z|b)onde z == a % b. Por essa propriedade, e conforme explicado aqui e aqui , aé um resíduo quadrático de bse zé, mesmo assim a >= b.

(-1|b)= 1se b == 0,1,2 (mod 4)e -1se b == 3 (mod 4). (0|b)é 0com exceção de (0|1)que é 1, porque (a|1)é sempre 1e para negativo a, (-a|b) == (-1|b) * (a|b).

A saída do símbolo Kronecker é sempre -1, 0 or 1, onde a saída é 0if ae bpossui fatores comuns. Se bé um primo ímpar, (a|b) == 1se aé um resíduo quadrático mod b, e -1se for, não é um resíduo quadrático.

Regras

  • Seu código deve ser um programa ou uma função.

  • As entradas devem estar na ordem a b.

  • A saída deve ser -1, 0ou 1.

  • Isso é código de golfe, portanto, seu código não precisa ser eficiente, apenas curto.

  • Nenhum built-in que calcule diretamente o Kronecker ou os símbolos Jacobi e Legendre relacionados. Outros built-ins (para fatoração principal, por exemplo) são justos.

Exemplos

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

Essa é uma função complicada. Por favor, deixe-me saber se algo não está claro.

Sherlock9
fonte
Tem certeza de que não deseja proibir os built-ins? reference.wolfram.com/language/ref/KroneckerSymbol.html
Martin Ender
@ MartinBüttner Eu estava editando exemplos quando vi seu comentário. Não permitirei que os built-ins calculem diretamente os símbolos Kronecker, Jacobi ou Legendre, mas qualquer outra coisa (incluindo funções primordiais de fatoração) deve ser um jogo justo.
Sherlock9
não sei ao certo por que (31 | 5) fornece 1. Não deve haver um resíduo qudrático, então por que não é -1?
Eumel
Também 7/19 deve ser 1 e 19/7 deve ser -1 de acordo com o wiki é ligada
Eumel
3
Se as soluções precisarem lidar com entradas negativas e zero corretamente, você definitivamente deve adicionar alguns casos de teste para isso.
Martin Ender

Respostas:

2

CJam (70 bytes)

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

Demonstração online (casos de teste gerados com o Mathematica).

Dissecação

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

Encontrei várias maneiras de avaliar (a|2)a mesma contagem de caracteres e optei por usar a com a apresentação mais clara.

integer array <W= O IMO é uma maneira bastante elegante de fazer fallbacks: se o número inteiro for maior que o comprimento da matriz, selecionamos o último elemento.

Outros comentários

É decepcionante que, para o prime ímpar, po estilo Fermat direto (a|p)seja tão curto, porque existe uma maneira muito divertida de encontrar o (a|n)positivo positivo nque eu queria usar. A base é o lema de Zolotarev:

Se pé um primo ímpar e aé um coprime inteiro para, pentão o símbolo Legendre (a|p)é o sinal da permutaçãox -> ax (mod p)

Isso foi reforçado por Frobenius para

Se ae bsão inteiros ímpares positivos em relação ao coprime, o símbolo de Jacobi (a|b)é o sinal da permutaçãox -> ax (mod b)

e por Lerch para

Se bé um número inteiro ímpar positivo e aé um coprime inteiro para, bentão o símbolo de Jacobi (a|b)é o sinal da permutaçãox -> ax (mod b)

Veja Brunyate e Clark, Estendendo a abordagem de Zolotarev-Frobenius à reciprocidade quadrática , The Ramanujan Journal 37.1 (2014): 25-50 para referências.

E pode ser facilmente fortalecido um passo adiante (embora eu não tenha visto isso na literatura) para

Se bé um número inteiro ímpar positivo e aé um número inteiro, o símbolo Jacobi (a|b)é o símbolo Levi-Civita do mapa x -> ax (mod b).

Prova: se aé coprime, bentão usamos Zolotarev-Frobenius-Lerch; caso contrário, o mapa não é uma permutação e o símbolo Levi-Civita é 0o desejado.

Isso fornece o cálculo do símbolo de Jacobi

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

Mas o tratamento especial necessário (a|-1)e (a|2)significa que eu não encontrei uma maneira de calcular o símbolo Kronecker, que é mais curto com essa abordagem: é mais curto fatorar e tratar os números primos individualmente.

Peter Taylor
fonte
4

Python 3, 747 369 335 bytes

Como resposta de exemplo, apenas jogue um pouco e para ter uma idéia de como será a resposta.

E sim, os bits de fatoração principal e de codificação do comprimento da execução são extraídos do Pyth com desculpas pelo 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
fonte
4
Desculpas aceitas - fico feliz que alguém leia o código fonte do Pyth.
Isaacg
2

Mathematica, 169 175 165 bytes

(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)
alefalpha
fonte
2

LabVIEW, 44 bytes Primitivas do LabVIEW

Desde a sua simetria, troquei as entradas se a fosse maior que b.

Representa a fórmula real agora

contando como sempre de acordo com

para o caso verdadeiro

Eumel
fonte
Infelizmente, (a|b) != (b|a)em todos os casos. Na maioria dos casos, sim, mas não em todos eles. Embora funcionasse se você reduzisse em a mod bvez de trocá-los.
Sherlock9
desde que eu tenho o explantion agora eu possa editá-lo, dá-me um min
Eumel
11
Existe alguma maneira de testar isso? Eu realmente não entendo como o LabView funciona.
Sherlock9
Essa é uma boa pergunta, eu posso pensar em duas maneiras. Primeiro eu posso criar um .exe e enviá-lo para você, depois você pode obter uma versão de teste do Labview e eu posso enviar o vi ou você pode reconstruí-lo a partir da foto.
Eumel
7
Isso não é 44 bytes. Se você definir um sistema de pontuação que não seja baseado no tamanho do arquivo, deverá chamá-lo de algo diferente de bytes.
feersum
1

Julia, 195 bytes

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

Esta é uma função recursiva kque aceita dois números inteiros e retorna um número inteiro.

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

Haskell, 286 bytes

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)

Provavelmente não completamente otimizado, mas um esforço valente. O símbolo Kronecker é definido como a função infix a # b, ou seja,

*Main>323#455265 
1
killmous
fonte