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.


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.


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

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)

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


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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.