Дискретна згортання або поліноміальне множення


19

З огляду на два непорожні списки цілих чисел, ваше представлення повинно обчислити та повернути дискретну згортку двох. Цікаво, що якщо розглядати елементи списку як коефіцієнти многочленів, то згортання двох списків являє собою коефіцієнти добутку двох многочленів.

Визначення

З огляду на списки A=[a(0),a(1),a(2),...,a(n)]та B=[b(0),b(1),b(2),...,b(m)](встановлення a(k)=0 for k<0 and k>nта b(k)=0 for k<0 and k>m), згортання двох визначається як A*B=[c(0),c(1),...,c(m+n)]деc(k) = sum [ a(x)*b(y) for all integers x y such that x+y=k]

Правила

  • Дозволено будь-яке зручне форматування вводу та виводу для вашої мови.
  • Вбудовані модулі для згортання, створення матриць згортки, співвідношення та множення поліномів не допускаються.

Приклади

[1,1]*[1] = [1,1]
[1,1]*[1,1] = [1,2,1]
[1,1]*[1,2,1] = [1,3,3,1]
[1,1]*[1,3,3,1] = [1,4,6,4,1]
[1,1]*[1,4,6,4,1] = [1,5,10,10,5,1]

[1,-1]*[1,1,1,1,1] = [1,0,0,0,0,-1]
[80085,1337]*[-24319,406] = [-1947587115,7,542822]

3
Специфікація передбачає, що входи довжиною n, m повинні давати вихід довжиною n + m - 1, але це не стосується вашого тестового випадку [1,1]*[] = [], і, можливо, не може утримувати []*[] = ?. У порожніх списках згортання недостатньо чітко визначено. Я думаю, ви повинні гарантувати, що вхідні списки непусті.
Андерс Касеорг

1
@AndersKaseorg Ви праві, я це зміню.
flawr

Відповіді:


14

J, 10 8 байт

[:+//.*/

Використання:

ppc =: [:+//.*/    NB. polynomial product coefficients 
80085 1337 ppc _24319 406
_1947587115 7 542822

Опис: Програма займає два списки, складає таблицю множення, потім додає числа на додатні діагоналі.


Дуже розумний підхід!
Луїс Мендо

Не потрібно рахувати дужки. Вираз усередині них оцінюється як мовчазне дієслово, яке може бути присвоєне змінній.
Денніс

Чудовий приклад прислівників!
миль

6

MATL , 19 байт

PiYdt"TF2&YStpsw]xx

Спробуйте в Інтернеті!

Пояснення

Це створює блок-діагональну матрицю з двома входами, реверсуючи перший. Наприклад, з входами [1 4 3 5], [1 3 2]матриця

[ 5 3 4 1 0 0 0
  0 0 0 0 1 3 2 ]

Кожен запис згортки виходить, зміщуючи перший рядок на одну позицію праворуч, обчислюючи добуток кожного стовпця та підсумовуючи всі результати.

В принципі, зміщення слід робити набиванням нулями зліва. Еквівалентно, кругові можна використовувати зсув, оскільки матриця містить нулі у відповідних записах.

Наприклад, перший результат отримують зі зміщеної матриці

[ 0 5 3 4 1 0 0
  0 0 0 0 1 3 2 ]

і є таким чином 1*1 == 1. Другий отриманий від

[ 0 0 5 3 4 1 0
  0 0 0 0 1 3 2 ]

і це, таким чином 4*1+1*3 == 7, і т. д. Це потрібно робити в m+n-1рази, де mі nє вхідні довжини. Код використовує цикл з m+nітераціями (що зберігає деякі байти) і відкидає останній результат.

P          % Take first input (numeric vactor) implicitly and reverse it
i          % Take second input (numeric vactor) 
Yd         % Build diagonal matrix with the two vectors
t          % Duplicate
"          % For each column of the matrix
  TF2&YS   %   Circularly shift first row 1 step to the right
  t        %   Duplicate
  p        %   Product of each column
  s        %   Sum all those products
  w        %   Swap top two elements in stack. The shifted matrix is left on top
]          % End for
xx         % Delete matrix and last result. Implicitly display

4

Haskell, 55 49 байт

(a:b)#c=zipWith(+)(0:b#c)$map(a*)c++[]#b
_#c=0<$c

Визначає оператора #.


1
Я думаю, що підкладка [0,0..]може (0<$b)надати саме потрібну довжину, що дозволяє порожній базовий корпус _#b=0<$b.
xnor

@xnor Дійсно, це економить 6 байт.
Андерс Касеорг

Тепер, коли я нарешті зрозумів вашу відповідь, мушу сказати, що це просто так проклято розумно! Я вражений!
невдача

3

Матлаб / Октава, 41 байт

@(p,q)poly([roots(p);roots(q)])*p(1)*q(1)

Це визначає анонімну функцію. Щоб викликати його, призначте його змінній або використовуйте ans.

Спробуйте тут .

Пояснення

Це експлуатує факти, які

  • Коріння (можливо, повторювані) характеризують поліном до його провідного коефіцієнта.
  • Добуток двох многочленів має коріння обох.

Код обчислює коріння двох многочленів (функції roots) та об'єднує їх у масив стовпців. З цього отримують коефіцієнти многочлена продукту з провідною 1(функцією poly). Нарешті результат множать на провідні коефіцієнти двох многочленів.


3

Октава , 48 байт

@(p,q)ifft(fft([p q*0]).*fft([q p*0]))(1:end-1)

Спробуйте тут .

Пояснення

Дискретна згортання відповідає множенню (дискретного часу) перетворень Фур'є. Таким чином, одним із способів множення поліномів було б їх перетворення, множення трансформованих послідовностей та перетворення назад.

Якщо використовувати дискретне перетворення Фур'є (DFT) замість перетворення Фур'є, то результат кругової згортки вихідних послідовностей поліноміальних коефіцієнтів. Код слідує за цим маршрутом. Щоб зробити кругову згортку рівним стандартній згортці, послідовності занурені в нуль і результат обрізаний.


Чорт, я все-таки мав би заборонити Fft, але хороша робота!
flawr

@flawr Так, я думаю, ми говорили про це ...? :-P
Луїс Мендо

2

05AB1E , 18 17 байт

Код

0Ev²¹g<Å0«y*NFÁ}+

Пояснення

Теорія:

Щоб знайти згортку, давайте розглянемо приклад [1, 2, 3], [3, 4, 5]. Значення першого масиву ми розміщуємо догори дном і вертикально так:

3
2
1

Тепер розміщуємо другий масив як сходи і множимо його на:

3 ×       [3  4  5]
2 ×    [3  4  5]
1 × [3  4  5]

Результат:

        9   12   15
    6   8   10
3   4   5

Потім ми додаємо їх у результаті:

        9   12   15
    6   8   10
3   4   5       

3   10  22  22   15

Отже, згортка є [3, 10, 22, 22, 15].

Сам код:

Ми будемо робити цей крок за кроком, використовуючи [1, 2, 3], [3, 4, 5]як тестовий випадок.

0Ev²¹g<Å0«y*NFÁ}+

Спочатку натискаємо, 0а потім Eоцінюємо перший вхідний масив. Зображуємо кожен елемент за допомогою v.

Отже, для кожного елемента ми натискаємо другий масив з, ²а потім довжину першого масиву, використовуючи ¹gта зменшуючи його на 1 (з <). Ми перетворюємо це в список нулів з (довжина 1-го масиву - 1) нулями, використовуючи Å0та додаючи це до нашого списку. Тепер наш стек виглядає таким чином для першого елемента в списку введення:

[3, 4, 5, 0, 0]

Ми множимо цей масив на поточний елемент, виконаний за допомогою y*. Після цього ми натискаємо N, що вказує на індекс поточного елемента (нульовий показник) і обертаємо масив, який багато разів вправо, використовуючи FÁ}. Нарешті, ми додаємо це до нашого початкового значення ( 0). Отже, що в основному робиться, це наступне:

[0, 0, 9, 12, 15] +
[0, 6, 8, 10, 0] +
[3, 4, 5, 0, 0] =

[3, 10, 22, 22, 15]

Що потім неявно друкується. Використовує кодування CP-1252 . Спробуйте в Інтернеті! .


2

Желе , 9 байт

0;+
×'Ṛç/

Спробуйте в Інтернеті! або перевірити всі тестові випадки .

Як це працює

×'Ṛç/  Main link. Arguments: p, q (lists)

×'     Spawned multiplication; multiply each item of p with each item of q.
  Ṛ    Reverse the rows of the result.
   ç/  Reduce the rows by the helper link.


0;+    Helper link. Arguments: p, q (lists)

0;     Prepend a 0 to p.
  +    Perform vectorized addition of the result and q.

Що‽ желе довше J‽ Це неможливо за визначенням!
Адама

2

Лушпиння , 5 байт

mΣ∂Ṫ*

Спробуйте в Інтернеті!

Примітка: Подаючи нульово-поліном / порожній список, потрібно вказати його тип (тобто []:LN)!

Пояснення

mΣ∂Ṫ*  -- implicit inputs xs ys, for example: [1,-1] [1,1]
   Ṫ*  -- compute the outer product xsᵀ·ys: [[1,1],[-1,-1]]
  ∂    -- diagonals: [[1],[1,-1],[-1]]
mΣ     -- map sum: [1,0,1]

2

Матлаб, 33 байти

@(x,y)sum(spdiags(flip(x').*y),1)

Спробуйте в Інтернеті!

Створює матрицю всіх добірних елементів входів, а потім підсумовує по діагоналях. В ,1кінці змушує matlab підсумовувати правильний напрямок, коли один з вхідних векторів має довжину 1.

В Octave spdiagsне працює для векторів, що призводить до помилки, коли один з входів має довжину 1. Для явного розширення продукту, необхідного для елементів, потрібен Matlab 2016b або новіший.


Приємний підхід !!
Луїс Мендо


1

Пітон, 90 байт

lambda p,q:[sum((p+k*[0])[i]*(q+k*[0])[k-i]for i in range(k+1))for k in range(len(p+q)-1)]

1

JavaScript (ES6), 64 байти

(a,b)=>a.map((n,i)=>b.map((m,j)=>r[j+=i]=m*n+(r[j]||0)),r=[])&&r

Повертає порожній масив, якщо будь-який вхід порожній. Виходячи з моєї відповіді на поліноміацепцію .



1

Clojure, 104 байти

#(vals(apply merge-with +(sorted-map)(for[i(range(count %))j(range(count %2))]{(+ i j)(*(% i)(%2 j))})))

Об’єднання до sorted-mapгарантій повернення значень у правильному порядку. Мені б хотілося, щоб було ще кілька тестових випадків.

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