Обчисліть символ Kronecker


9

Відповідні посилання тут і тут , але ось коротка версія:

У вас є вхід двох цілих чисел aі bміж негативною нескінченністю та нескінченністю (хоча за потреби я можу обмежити діапазон, але функція все одно повинна приймати негативні введення).

Визначення символу Kronecker

Ви повинні повернути символ Kronecker (a|b)для входів aі 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і p_iі e_iє простими елементами та експонентами в основній факторизації b.

Для непарного розквіту p, (a|p)=a^((p-1)/2) (mod p)як визначено тут .

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

для b == -1,(n|-1)={-1 for n<0; 1 for n>0

Якщо a >= b, (a|b) == (z|b)де z == a % b. За цією властивістю, як пояснено тут і тут , aє квадратичним залишком, bякщо zє, хоча a >= b.

(-1|b)= 1якщо b == 0,1,2 (mod 4)і -1якщо b == 3 (mod 4). (0|b)є , 0за винятком (0|1)що 1, тому що (a|1)завжди 1і для негативних a, (-a|b) == (-1|b) * (a|b).

Вихід символу Kronecker завжди -1, 0 or 1, де вихід є, 0якщо aі bє якісь загальні фактори. Якщо bє непарне просте, (a|b) == 1якщо aє квадратичним залишком мода b, і -1якщо це не квадратичний залишок.

Правила

  • Ваш код повинен бути програмою або функцією.

  • Входи повинні бути в порядку a b.

  • Вихід повинен бути або -1, 0або 1.

  • Це кодовий гольф, тому ваш код не повинен бути ефективним, просто коротким.

  • Немає вбудованих модулів, які безпосередньо обчислюють Kronecker або пов'язані з ними символи Jacobi та Legendre. Інші вбудовані модулі (наприклад, для основної факторизації) - це чесна гра.

Приклади

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

Це складна функція, тому, будь ласка, повідомте мене, якщо щось незрозуміле.


Ви впевнені, що не хочете заборонити вбудовані модулі? reference.wolfram.com/language/ref/KroneckerSymbol.html
Мартін Ендер

@ MartinBüttner Я редагував приклади, коли побачив ваш коментар. Я забороняю вбудовані модулі, які безпосередньо обчислюють символи Kronecker, Jacobi або Legendre, але все, що завгодно (включаючи функції основної факторизації), має бути чесною грою.
Шерлок9

Я не зовсім впевнений, чому (31 | 5) дає 1. Не повинно бути квадратичного залишку, то чому ж це не -1?
Евмель

також 7/19 має бути 1, а 19/7 має бути -1 відповідно до вікі, яку ви пов’язали
Eumel

3
Якщо рішення повинні правильно поводитись з негативними та нульовими входами, для цього обов'язково слід додати кілька тестових випадків.
Мартін Ендер

Відповіді:


2

CJam (70 байт)

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

Демонстрація в Інтернеті (тестові випадки, створені за допомогою Mathematica).

Розсічення

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

Я знайшов кілька способів оцінювання (a|2)для одного і того ж числа символів і вирішив використовувати той, який має найяснішу презентацію.

integer array <W= IMO - це досить елегантний спосіб робити резервні копії: якщо ціле число більше довжини масиву, ми вибираємо останній елемент.

Інші коментарі

Розчаровує те, що для непарного прем'єру pпрямий стиль Ферма (a|p)такий короткий, тому що існує дуже гострий спосіб пошуку (a|n)позитивного дива, nякий я хотів використати. Основа леми Золотарева:

Якщо pє непарне простим і aє цілим копрімесом, pто символ Legendre (a|p)є знаком перестановкиx -> ax (mod p)

Це посилило Фробеніус до

Якщо aі bє копійними додатними непарними цілими числами, то символ Якобі (a|b)є знаком перестановкиx -> ax (mod b)

і Лерчем до

Якщо bце ціле додатне непарне ціле число і aє цілим числом, bто символ Якобі (a|b)є знаком перестановкиx -> ax (mod b)

Див. Бруньяте і Кларка, розширюючи підхід Золотарева-Фробеніуса до квадратичної взаємності , журнал "Рамануджан" 37.1 (2014): 25-50 для довідок.

І його можна легко посилити на крок далі (хоча я цього не бачив у літературі) до

Якщо bце натуральне ціле число і aє цілим числом, то символ Якобі (a|b)- це символ Леві-Цівіта на картіx -> ax (mod b) .

Доказ: якщо aкопрім доb тоді ми використовуємо Золотарев-Фробеніус-Лерч; інакше карта не є перестановкою, а символ Леві-Цівіта - 0як бажано.

Це дає розрахунок символу Якобі

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

Але спеціальне звернення, яке вимагається (a|-1)і (a|2)означає, що я не знайшов способу обчислити символ Кронекера, який коротший при такому підході: коротше розфасовувати та лікувати праймери індивідуально.


4

Пітон 3, 747 369 335 байт

Як приклад відповіді, лише трохи гольф, і щоб дати вам уявлення про те, як буде виглядати відповідь.

І так, прості розбиття бітів і кодування довжини кодуються з Pyth з вибаченнями на 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
Вибачення прийнято - я радий, що хтось читає вихідний код Pyth.
isaacg

2

Математика, 169 175 165 байт

(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 байт Примітиви LabVIEW

Оскільки його симетричний я поміняв входи, якщо a більше b.

Представляє реальну формулу зараз

підрахунок як завжди згідно

для справжнього випадку


На жаль, (a|b) != (b|a)у всіх випадках. У більшості випадків так, але не у всіх. Хоча це спрацює, якби ви скоротили a mod bзамість того, щоб замінювати їх.
Шерлок9

оскільки у мене є пояснення, я зараз можу його відредагувати, дайте мені хв.
Eumel

1
Чи є спосіб я перевірити це? Я не дуже розумію, як працює LabView.
Шерлок9

це гарне питання, я можу придумати два способи. По-перше, я можу створити .exe і надіслати його вам, по-друге, ви можете отримати тестову версію лабораторії, і я можу надіслати вам vi або ви можете відновити його з рис.
Евмель

7
Це не 44 байти. Якщо ви визначаєте систему підрахунку балів, яка не ґрунтується на розмірі файлу, вам слід назвати це щось інше, ніж байти.
feersum

1

Юлія, 195 байт

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

Це рекурсивна функція, kяка приймає два цілі числа і повертає ціле число.

Безголівки:

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 байт

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)

Напевно, не повністю оптимізований, але доблесний зусилля. Символ Kronecker визначається як функція інфікування a # b, тобто

*Main>323#455265 
1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.