Calculate the Kronecker symbol

9

Relevant links here and here, but here is the short version:

You have an input of two integers a and b between negative infinity and infinity (though if necessary, I can restrict the range, but the function must still accept negative inputs).

Definition of the Kronecker symbol

You must return the Kronecker symbol (a|b) for inputs a and b where

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

where b = p_1^e_1 * p_2^e_2 * ... * p_n^e_n, and p_i and e_i are the primes and exponents in the prime factorization of b.

For an odd prime p, (a|p)=a^((p-1)/2) (mod p) as defined here.

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

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

If a >= b, (a|b) == (z|b) where z == a % b. By this property, and as explained here and here, a is a quadratic residue of b if z is, even though a >= b.

(-1|b) = 1 if b == 0,1,2 (mod 4) and -1 if b == 3 (mod 4). (0|b) is 0 except for (0|1) which is 1, because (a|1) is always 1 and for negative a, (-a|b) == (-1|b) * (a|b).

The output of the Kronecker symbol is always -1, 0 or 1, where the output is 0 if a and b have any common factors. If b is an odd prime, (a|b) == 1 if a is a quadratic residue mod b, and -1 if is it is not a quadratic residue.

Rules

  • Your code must be a program or a function.

  • The inputs must be in the order a b.

  • The output must be either -1, 0 or 1.

  • This is code golf, so your code does not have to be efficient, just short.

  • No built-ins that directly calculate the Kronecker or the related Jacobi and Legendre symbols. Other built-ins (for prime factorization, for example) are fair game.

Examples

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

This is a complicated function, so please let me know if anything is unclear.

Sherlock9

Posted 2015-11-30T18:33:04.143

Reputation: 11 664

Are you sure you don't want to disallow built-ins? https://reference.wolfram.com/language/ref/KroneckerSymbol.html

– Martin Ender – 2015-11-30T18:54:13.650

@MartinBüttner I was editing in examples when I saw your comment. I will disallow built-ins that directly calculate the Kronecker, Jacobi or Legendre symbols, but anything else (including prime factorization functions) should be fair game. – Sherlock9 – 2015-11-30T18:55:54.353

im not entirely sure why (31|5) gives 1. There shouldnt be a qudratic residue so why isnt it -1? – Eumel – 2015-11-30T19:51:06.683

also 7/19 should be 1 and 19/7 should be -1 according to the wiki you linked – Eumel – 2015-11-30T20:03:15.303

@Eumel 31 is a quadratic residue mod 5, because it is congruent to 1 mod 5. I have edited the question to explain this. – Sherlock9 – 2015-11-30T20:04:01.270

@Eumel Ah, you are correct. I'll edit the examples. – Sherlock9 – 2015-11-30T20:04:46.830

3If solutions have to handle negative and zero inputs correctly, you should definitely add some test cases for that. – Martin Ender – 2015-11-30T20:12:05.247

I think kronecker(0, 12) is 0. – alephalpha – 2015-12-01T04:27:08.253

I don't think you've actually defined the symbol for a < 0. – Peter Taylor – 2015-12-09T00:12:21.553

Half-way there. If you now define (-1|b) I think the spec will be complete. – Peter Taylor – 2015-12-09T15:24:48.940

Only very rarely does PPCG make me feel very, very stupid, as if I were browsing Math.SE, but this is one of those rare cases

– cat – 2015-12-19T20:52:04.620

Answers

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=~}:*}

Online demo (test cases generated with 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
}

I found several ways of evaluating (a|2) for the same character count, and have chosen to use the one with the clearest presentation.

integer array <W= is IMO a quite elegant way of doing fallbacks: if the integer is greater than the length of the array, we select the last element.

Other comments

It's disappointing that for odd prime p the direct Fermat-style (a|p) is so short, because there's a very golfy way of finding (a|n) for positive odd n which I wanted to use. The basis is Zolotarev's lemma:

If p is an odd prime and a is an integer coprime to p then the Legendre symbol (a|p) is the sign of the permutation x -> ax (mod p)

This was strengthened by Frobenius to

If a and b are coprime positive odd integers then the Jacobi symbol (a|b) is the sign of the permutation x -> ax (mod b)

and by Lerch to

If b is a positive odd integer and a is an integer coprime to b then the Jacobi symbol (a|b) is the sign of the permutation x -> ax (mod b)

See Brunyate and Clark, Extending the Zolotarev-Frobenius approach to quadratic reciprocity, The Ramanujan Journal 37.1 (2014): 25-50 for references.

And it can easily be strengthened one step further (although I haven't seen this in the literature) to

If b is a positive odd integer and a is an integer then the Jacobi symbol (a|b) is the Levi-Civita symbol of the map x -> ax (mod b).

Proof: if a is coprime to b then we use Zolotarev-Frobenius-Lerch; otherwise the map is not a permutation, and the Levi-Civita symbol is 0 as desired.

This gives the Jacobi symbol calculation

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

But the special treatment required for (a|-1) and (a|2) mean that I haven't found a way of calculating the Kronecker symbol which is shorter with this approach: it's shorter to factorise and treat the primes individually.

Peter Taylor

Posted 2015-11-30T18:33:04.143

Reputation: 41 901

4

Python 3, 747 369 335 bytes

As an example answer, only slightly golfed, and to give you an idea of what an answer will look like.

And yes, the prime factorization and run-length-encoding bits are cribbed from Pyth with apologies to 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

Posted 2015-11-30T18:33:04.143

Reputation: 11 664

4Apology accepted - I'm glad someone reads Pyth source code. – isaacg – 2015-11-30T20:19:56.707

3

LabVIEW, 44 Bytes LabVIEW Primitives

Since its symetrical i swapped the inputs if a was bigger than b.

Represents the real formula now

counting like always according to

for true case

Eumel

Posted 2015-11-30T18:33:04.143

Reputation: 2 487

Unfortunately, (a|b) != (b|a) in all cases. In most cases, yes, but not in all of them. Though it would work if you reduced a mod b instead of swapping them. – Sherlock9 – 2015-11-30T20:15:02.270

since i have the explantion now i can edit it, give me a min – Eumel – 2015-11-30T20:16:58.907

1Is there any way I can test this? I don't really understand how LabView works. – Sherlock9 – 2015-11-30T20:45:34.580

that is a good question, i can think of 2 ways. First i can build an .exe and send it to you, second you can get a labview test version and i can send you the vi or you can rebuild it from the pic. – Eumel – 2015-11-30T21:49:52.260

6This is not 44 bytes. If you define a scoring system that is not based on the size of the file, you should call it something other than bytes. – feersum – 2015-11-30T21:57:10.477

For the moment, I will take your word for it. Send me the .exe anyway, but you have my upvote. – Sherlock9 – 2015-11-30T21:58:32.153

I thought there was a messanging system here but there isnt, how do i actually send it to you? – Eumel – 2015-12-01T09:06:27.910

@Eumel Seeing as you put up a gif for some of your other LabVIEW solutions, can you put one up here? And change the heading from bytes to LabVIEW primitives? – Sherlock9 – 2015-12-09T06:19:19.593

will do when im at home – Eumel – 2015-12-09T09:21:06.717

The gif appears to be for a different version to the image above. And if I'm correctly interpreting the symbols, this seems to be incapable of giving any output other than -1 or 1, which means that it must be giving incorrect outputs for some inputs. – Peter Taylor – 2015-12-19T10:22:32.783

And from looking at a reference, it seems to have some case structures for which the image only shows one case, so you haven't posted the full code.

– Peter Taylor – 2015-12-19T10:43:10.710

The other case is just a 0 nothing more ill put it up though – Eumel – 2015-12-19T19:58:40.977

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)

alephalpha

Posted 2015-11-30T18:33:04.143

Reputation: 23 988

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

This is a recursive function k that accepts two integers and returns an integer.

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.

Posted 2015-11-30T18:33:04.143

Reputation: 23 761

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)

Probably not completely optimized, but a valiant effort. The Kronecker symbol is defined as the infix function a#b, i.e.

*Main>323#455265 
1

killmous

Posted 2015-11-30T18:33:04.143

Reputation: 369