Определитель целочисленной матрицы

34

Если в качестве входных данных задана квадратная целочисленная матрица, выведите определитель матрицы.

правила

  • Вы можете предположить, что все элементы в матрице, определитель матрицы и общее количество элементов в матрице находятся в пределах представимого диапазона целых чисел для вашего языка.
  • Разрешается вывод десятичного значения / значения с плавающей запятой с дробной частью 0 (например, 42.0вместо 42).
  • Встроенные функции разрешены, но рекомендуется включать решение, не использующее встроенные функции.

Тестовые случаи

[[42]] -> 42
[[2, 3], [1, 4]] -> 5
[[1, 2, 3], [4, 5, 6], [7, 8, 9]] -> 0
[[13, 17, 24], [19, 1, 3], [-5, 4, 0]] -> 1533
[[372, -152, 244], [-97, -191, 185], [-53, -397, -126]] -> 46548380
[[100, -200, 58, 4], [1, -90, -55, -165], [-67, -83, 239, 182], [238, -283, 384, 392]] -> 571026450
[[432, 45, 330, 284, 276], [-492, 497, 133, -289, -28], [-443, -400, 56, 150, -316], [-344, 316, 92, 205, 104], [277, 307, -464, 244, -422]] -> -51446016699154
[[416, 66, 340, 250, -436, -146], [-464, 68, 104, 471, -335, -442], [159, -407, 310, -489, -248, 370], [62, 277, 446, -325, 47, -193], [460, 460, -418, -28, 234, -374], [249, 375, 489, 172, -423, 125]] -> 39153009069988024
[[-246, -142, 378, -156, -373, 444], [186, 186, -23, 50, 349, -413], [216, 1, -418, 38, 47, -192], [109, 345, -356, -296, -47, -498], [-283, 91, 258, 66, -127, 79], [218, 465, -420, -326, -445, 19]] -> -925012040475554
[[-192, 141, -349, 447, -403, -21, 34], [260, -307, -333, -373, -324, 144, -190], [301, 277, 25, 8, -177, 180, 405], [-406, -9, -318, 337, -118, 44, -123], [-207, 33, -189, -229, -196, 58, -491], [-426, 48, -24, 72, -250, 160, 359], [-208, 120, -385, 251, 322, -349, -448]] -> -4248003140052269106
[[80, 159, 362, -30, -24, -493, 410, 249, -11, -109], [-110, -123, -461, -34, -266, 199, -437, 445, 498, 96], [175, -405, 432, -7, 157, 169, 336, -276, 337, -200], [-106, -379, -157, -199, 123, -172, 141, 329, 158, 309], [-316, -239, 327, -29, -482, 294, -86, -326, 490, -295], [64, -201, -155, 238, 131, 182, -487, -462, -312, 196], [-297, -75, -206, 471, -94, -46, -378, 334, 407, -97], [-140, -137, 297, -372, 228, 318, 251, -93, 117, 286], [-95, -300, -419, 41, -140, -205, 29, -481, -372, -49], [-140, -281, -88, -13, -128, -264, 165, 261, -469, -62]] -> 297434936630444226910432057
Мего
источник
существует ли максимальный размер матрицы, который необходимо поддерживать, или это произвольно?
Тейлор Скотт
1
@TaylorScott Первое правило в списке:You may assume that all elements in the matrix, the determinant of the matrix, and the total number of elements in the matrix are within the representable range of integers for your language.
Мего
4
Вы знаете, что у вас есть интересный вызов, когда у вас есть 4 ответа Желе, последовательно вне игры в гольф друг с другом ...
полностью человек

Ответы:

25

Желе , 15 байт

LŒ!ðŒcIṠ;ị"Pð€S

Попробуйте онлайн!

Как это работает

LŒ!ðŒcIṠ;ị"Pð€S   input
L                 length
 Œ!               all_permutations
   ð        ð€    for each permutation:
    Œc                take all unordered pairs
      I               calculate the difference between
                      the two integers of each pair
       Ṡ              signum of each difference
                      (positive -> 1, negative -> -1)
        ;             append:
         ị"             the list of elements generated by taking
                        each row according to the index specified
                        by each entry of the permutation
           P          product of everything
              S   sum

Почему это работает - математическая версия

Оператор det берет матрицу и возвращает скаляр. Матрица n- by- n может рассматриваться как набор из n векторов длины n , поэтому det действительно является функцией, которая берет n векторов из ℤ n. и возвращает скаляр.

Поэтому я пишу det ( v 1 , v 2 , v 3 , ..., v n ) для det [ v 1 v 2 v 3 ... v n ].

Обратите внимание, что det является линейным в каждом аргументе, то есть det ( v 1 + λ w 1 , v 2 , v 3 , ..., v n ) = det ( v 1 , v 2 , v 3 , ..., v n ) + λ det ( w 1 , v 2 , v 3 , ..., v n ). Следовательно, это линейное отображение из (ℤ n ) n к ℤ.

Достаточно определить изображение базиса по линейной карте. Базис (ℤ n ) n состоит из n- кратных тензорных произведений базисных элементов из ℤ n , т. Е. E 5 e 3 e 1 e 5 e 1 . Тензорные произведения, которые содержат идентичные тензоры, должны быть отправлены в ноль, поскольку определитель матрицы, в которой два столбца идентичны, равен нулю. Осталось проверить, на что отправляются тензорные произведения различных базисных элементов. Индексы векторов в тензорном произведении образуют биекцию, то есть перестановку, в которой четные перестановки отправляются в 1, а нечетные перестановки отправляются в -1.

Например, чтобы найти определитель [[1, 2], [3, 4]]: обратите внимание, что столбцами являются [1, 3] и [2, 4]. Разложим [1, 3], чтобы получить (1 e 1 + 3 e 2 ) и (2 e 1 + 4 e 2 ). Соответствующий элемент в тензорном произведении равен (1 e 1 ⊗ 2 e 1 + 1 e 1 ⊗ 4 e 2 + 3 e 2 ⊗ 2 e 1 + 3 e 2 ⊗ 4 e 2 ), который мы упрощаем до (2 e 1 1 e 1 + 4 e 1 ⊗ e 2 + 6 e 2 ⊗ e 1 + 12 e 2 ⊗ e 2). Следовательно:

det [[1, 2], [3, 4]]
= det (1 e 1 + 3 e 2 , 2 e 1 + 4 e 2 )
= det (2 e 1 ⊗ e 1 + 4 e 1 ⊗ e 2 + 6 e 2 ⊗ e 1 + 12 e 2 ⊗ e 2 )
= det (2 e 1 ⊗ e 1 ) + det (4 e 1 ⊗ e 2 ) + det (6 e 2 ⊗ e 1 ) + det (12 e22 e 2 )
= 2 det (e 1 ⊗ e 1 ) + 4 det (e 1 ⊗ e 2 ) + 6 det (e 2 ⊗ e 1 ) + 12 det (e 2 ⊗ e 2 )
= 2 (0) + 4 (1) + 6 (-1) + 12 (0)
= 4 - 6
= -2

Теперь осталось доказать, что формула для нахождения четности перестановки справедлива. То, что делает мой код, по сути, находит количество инверсий, то есть мест, где элемент слева больше, чем элемент справа (не обязательно последовательно).

Например, в перестановке 3614572 имеется 9 инверсий (31, 32, 61, 64, 65, 62, 42, 52, 72), поэтому перестановка является нечетной.

Обоснование состоит в том, что каждая транспозиция (замена двух элементов) либо добавляет одну инверсию, либо убирает одну инверсию, меняя четность числа инверсий, а четность перестановки - это четность числа транспозиций, необходимых для достижения перестановки.

Поэтому в заключение наша формула имеет вид:

Почему это работает - нематематическая версия

где σ является перестановкой 𝕊 п группы всех перестановок п букв и SGN является знаком перестановки, AKA (-1) , возведенная четности перестановки, и IJ является ( IJ ) записью в матрица ( я вниз, J поперек).

Дрянная Монахиня
источник
17
Эта «нематетическая версия» чертовски математика.
MD XF
6
@MDXF формулы и символы и числа вряд ли составляют математику. Математика - это абстракция, обобщение и логика формальных манипуляций с символами.
Утренняя монахиня
7
@JAB Jelly реализует свою собственную кодовую страницу . (На днях TIO будет включать ссылку на кодовую страницу ...)
17
1
@Mego «сумма диагональных произведений» работает только для матриц 1x1, 2x2 и 3x3. Для больших матриц необходимо учитывать все перестановки и их соотношение.
Утренняя монахиня
3
+1 для фактического включения доказательства в пост вместо того, чтобы говорить «поскольку эта формула указана на странице abcxyz, она должна быть истинной».
user202729
11

R , 3 байта

Простое решение

det

Попробуйте онлайн!

R , 94 92 байта

Внедренное решение

перехитрил Ярко Дуббельдам

d=function(m)"if"(x<-nrow(m),m[,1]%*%sapply(1:x,function(y)(-1)^(y-1)*d(m[-y,-1,drop=F])),1)

Попробуйте онлайн!

Рекурсивно использует разложение по несовершеннолетним вниз по первому столбцу матрицы.

f <- function(m){
 x <- nrow(m)                 # number of rows of the matrix
 if(sum(x) > 1){              # when the recursion reaches a 1x1, it has 0 rows
                              # b/c [] drops attributes
  minor <- function(y){
   m[y] * (-1)^(y-1) *
   d(m[-y,-1])                # recurse with the yth row and first column dropped
   }
  minors <- sapply(1:x,minor) # call on each row
  sum(minors)                 # return the sum
 } else {
  m                           # return the 1x1 matrix
 }
}

Giuseppe
источник
9

Желе , 16 15 12 10 байт

Ḣ×Zß-Ƥ$Ṛḅ-

Использует расширение Лапласа . Спасибо @miles за отыгрыш 3 5 байтов!

Попробуйте онлайн!

Как это работает

Ḣ×Zß-Ƥ$Ṛḅ-  Main link. Argument: M (matrix / 2D array)

Ḣ           Head; pop and yield the first row of M.
      $     Combine the two links to the left into a monadic chain.
  Z         Zip/transpose the matrix (M without its first row).
   ß-Ƥ      Recursively map the main link over all outfixes of length 1, i.e., over
            the transpose without each of its rows.
            This yields an empty array if M = [[x]].
 ×          Take the elementwise product of the first row and the result on the
            right hand. Due to Jelly's vectorizer, [x] × [] yields [x].
       Ṛ    Reverse the order of the products.
        ḅ-  Convert from base -1 to integer.
                [a]          -> (-1)**0*a
                [a, b]       -> (-1)**1*a + (-1)**0*b = b - a
                [a, b, c]    -> (-1)**2*a + (-1)**1*b + (-1)**0*c = c - b + a
                etc.
Деннис
источник
8

Wolfram Language (Mathematica) , между 14 и 42 байтами

У нас было 3-байтовое встроенное и 53-байтовое решение которое полностью избегает встроенных функций, так что вот несколько странных решений где-то посередине.

В Wolfram Language есть много очень интенсивных функций для разложения матриц на произведения других матриц с более простой структурой. Одним из более простых (то есть я слышал об этом раньше) является разложение Джордана. Каждая матрица аналогична (возможно, комплексной) верхней треугольной матрице, составленной из диагональных блоков с определенной структурой, называемой жордановым разложением этой матрицы. Сходство сохраняет определители, а определитель треугольной матрицы является произведением диагональных элементов, поэтому мы можем вычислить определитель со следующими 42 байтами :

1##&@@Diagonal@Last@JordanDecomposition@#&

Определитель также равен произведению собственных значений матрицы на кратность. К счастью, функция собственных значений Wolfram отслеживает кратность (даже для недиагонализируемых матриц), поэтому мы получаем следующее 20-байтовое решение:

1##&@@Eigenvalues@#&

Следующее решение - это обман, и я не совсем уверен, почему это работает. Вронскиан списка из n функций является определителем матрицы первых n -1 производных функций. Если мы дадим Wronskianфункции матрицу целых чисел и скажем, что переменная дифференцирования равна 1, каким-то образом она выплескивает определитель матрицы. Это странно, но не включает буквы " Det" и это всего лишь 14 байтов ...

#~Wronskian~1&

(The Casoratian детерминанта работает так же, для более 1 байт: #~Casoratian~1&)

В области абстрактной алгебры определитель матрицы n  x  n (рассматриваемой как отображение k → k, которая является умножением на определитель) является n- й внешней степенью матрицы (после выбора изоморфизма k → k n k н ). На языке Wolfram мы можем сделать это со следующими 26 байтами :

HodgeDual[TensorWedge@@#]&

И вот решение, которое работает только для положительных определителей. Если мы возьмем n- мерный единичный гиперкуб и применим к нему линейное преобразование, то n- мерный «объем» результирующей области является абсолютным значением определителя преобразования. Применение линейного преобразования к кубу дает параллелепипед, и мы можем взять его объем со следующими 39 байтами кода:

RegionMeasure@Parallelepiped[Last@#,#]&
Не дерево
источник
1
У меня было такое решение Exp@*Tr@*MatrixLog, но, к сожалению, это не работает для единичных матриц.
Миша Лавров
1
@MishaLavrov О, это умно! Я думаю, что вы можете исправить это с Check[E^Tr@MatrixLog@#,0]&.
не дерево
Замечательно! Я не знал об этом Checkраньше.
Миша Лавров
1
Я создал вызов для Jordan Decomposition некоторое время назад. Тебе это тоже может быть интересно. Какой отличный ответ!
Mego
8

Haskell , 71 байт

-3 байта благодаря Линн. Еще один байт пыли благодаря Крейг Рой.

f[]=1
f(h:t)=foldr1(-)[v*f[take i l++drop(i+1)l|l<-t]|(i,v)<-zip[0..]h]

Попробуйте онлайн! Добавлен -Oфлаг для оптимизации. Это не обязательно.

Объяснение (устарело)

f рекурсивно реализует расширение кофактора.

f[[x]]=x

Эта строка покрывает базовый случай матрицы 1 × 1 , и в этом случае определитель равен mat[0, 0].

f(h:t)=

При этом используется сопоставление с образцом в Haskell, чтобы разбить матрицу на голову (первую строку) и хвост (на остальную часть матрицы).

          [                                     |(i,v)<-zip[0..]h]

Перечислите заголовок матрицы (сжав бесконечный список целых чисел и заголовок) и переберите его.

           (-1)*i*v

Отрицательный результат зависит от того, является ли его индекс четным, поскольку вычисление определителя включает в себя чередование сложения и вычитания.

                     [take i l++drop(i+1)l|l<-t]

Это по существу удаляет i-й столбец хвоста, беря элементы i и объединяя его со строкой с первыми (i + 1) -ыми элементами, отброшенными для каждой строки в хвосте.

                   *f

Вычислить определитель результата выше и умножить его на результат (-1)*i*v.

       sum

Суммируйте результат из списка выше и возвращайте его.

totallyhuman
источник
2
вы могли бы сэкономить 1 байт , если заменить sum[(-1)^i*...сfoldr(-)0[...
Craig Roy
6

Протон , 99 байт

f=m=>(l=len(m))==1?m[0][0]:sum((-1)**i*m[0][i]*f([[m[k][j]for k:1..l]for j:0..l if j-i])for i:0..l)

Попробуйте онлайн!

-3 байта благодаря мистеру Xcoder
-3 байта благодаря Эрику Аутгольферу

Расширение по первому ряду

HyperNeutrino
источник
Просто потому, что у Протона нет встроенного детерминанта.
user202729
103 байта . ((~i%2)*2-1)->((-i%2)|1)
Г-н Xcoder
Также 102 байта путем замены j!=iна j-iили i-j.
г-н Xcoder
99 байтов
Эрик Outgolfer
@EriktheOutgolfer Ах да, спасибо!
ГиперНейтрино
5

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

@(x)round(prod(diag(qr(x))))

Попробуйте онлайн!

При этом используется QR - разложение матричного X в orthgonal матрицы Q и верхняя треугольная матрица R . Определитель X является произведением тех из Q и R . Ортогональная матрица имеет единичный определитель, а для треугольной матрицы определитель является произведением ее диагональных элементов. qrФункция Octave, вызываемая с одним выходом, дает R .

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

Луис Мендо
источник
1
Это интересный способ избежать detвстроенного. ;)
Томсминг
1
@tomsmeding :-) Кроме того, он уже был "использован" в ответе Стьюи
Луис Мендо
5

C  176  125 байт

Спасибо @ceilingcat за игру в гольф 42 байта и спасибо @Lynn и @Jonathan Frech за сохранение каждого байта!

d(M,n)int*M;{int i=n--,s=*M*!n,c,T[n*n];for(;i--;s+=M[i]*(1-i%2*2)*d(T,n))for(c=n*n;c--;T[c]=M[n-~c+c/n+(c%n>=i)]);return s;}

Вычисляет определитель, используя разложение Лапласа вдоль первого ряда.

Попробуйте онлайн!

раскатали:

d(M, n)int*M;
{
    int i=n--, s=*M*!n, c, T[n*n];
    for (; i--; s+=M[i]*(1-i%2*2)*d(T,n))
        for (c=n*n; c--;)
            T[c] = M[n-~c+c/n+(c%n>=i)];
    return s;
}
Steadybox
источник
(i%2*-2+1)(1-i%2*2)сохраняет еще один байт.
Линн
n+1+cможет быть n-~c.
Джонатан Фрех
Предлагаю i=sвместоreturn s
floorcat
5

Желе , 43 байта

Наконец-то я закончил писать свое не встроенное решение на языке игры в гольф!

ḣ⁹’’¤;ṫḊ€Ç×⁸ị@⁹’¤¤ḷ/¤
çЀ⁸J‘¤µJ-*×NS
ÇḢḢ$Ṗ?

Спасибо HyperNeutrino за сохранение байта!

Попробуйте онлайн! (интервал кода для ясности)

ужасно длинный способ удалить n-ые элементы из списка, улучшится позже


Этот ответ был превзойден ответами HyperNeutrino, Денниса и Лики Нун. Желе очень популярно как язык для игры в гольф.

Быстрое объяснение:

ÇḢḢ$Ṗ?    Main link.
     ?    If
    Ṗ     after remove the last element, the value is not empty (truthy)
Ç         then execute the last link
 ḢḢ$      else get the element at index [1, 1].

çЀ⁸J‘¤µJ-*×NS     Helper link 1, take input as a matrix.
çЀ                Apply the previous link, thread right argument to
   ⁸J‘¤            the range [2, 3, ..., n+1]
       µ           With the result,
        J-*        generate the range [-1, 1, -1, 1, ...] with that length
           ×N      Multiply by negative
             S     Sum

ḣ⁹’’¤;ṫḊ€Ç×⁸ị@⁹’¤¤ḷ/¤    Helper link 2, take left input as a matrix, right input as a number in range [2..n+1]
ḣ
 ⁹’’¤                    Take head ρ-2 of the matrix
     ;                   concatenate with 
      ṫ                  tail ρ (that is, remove item ρ-1)
       Ḋ€                Remove first column
         Ç               Calculate determinant of remaining matrix
          ×         ¤    multiply by
                  ḷ/     the first column,
            ị@           row #
              ⁹’¤        ρ-1 (just removed in determinant calculation routine) of
           ⁸     ¤       the matrix.
user202729
источник
4

Желе , 24 байта

œcL’$ṚÑ€
J-*×Ḣ€×ÇSµḢḢ$Ṗ?

Попробуйте онлайн!

объяснение

œcL’$ṚÑ€         Helper Link; get the next level of subdeterminants (for Laplace Expansion)
œc               Combinations without replacement of length:
  L’$            Length of input - 1 (this will get all submatrices, except it's reversed)
     Ṛ           Reverse the whole thing
      р         Get the determinant of each of these
J-*×Ḣ€×ÇSµḢḢ$Ṗ?  Main Link
              ?  If the next value is truthy
             Ṗ   Remove the last element (truthy if the matrix was at least size 2)
J-*×Ḣ€×ÇSµ       Then expand
          ḢḢ$    Otherwise, get the first element of the first element (m[0][0] in Python)
J                [1, 2, ..., len(z)]
 -*              (-1 ** z) for each z in the length range
   ×             Vectorizing multiply with
    Ḣ€           The first element of each (this gets the first column); modifies each row (makes it golfier yay)
      ×Ç         Vectorizing multiply with the subdeterminants
        S        Sum

-2 байта благодаря решению пользователя 202729

HyperNeutrino
источник
4

MATL , 3 байта / 5 байтов

Со встроенной функцией

&0|

Попробуйте онлайн!

Без встроенного

Спасибо Мише Лаврову за указание на ошибку, теперь исправленную

YvpYo

Попробуйте онлайн!

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

Yv       % Implicit input. Push vector containing the eigenvalues
p        % Product
Yo       % Round. Implicit display
Луис Мендо
источник
Разве произведение единичных значений не скажет вам только абсолютное значение определителя?
Миша Лавров
@MishaLavrov Ты совершенно прав! Спасибо, что заметили. Я исправил это, используя собственные значения вместо особых значений ... и это сэкономило 4 байта \ o /
Луис Мендо
4

R , 32 байта

function(m)Re(prod(eigen(m)$va))

Использует не Древовидный алгоритм взятия собственных значений матрицы и взятия реальной части их произведения.

Попробуйте онлайн!

JAD
источник
Очень элегантно! +1.
Джузеппе
3

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

@(x)-prod(diag([~,l,~]=lu(x)))

Попробуйте онлайн!

или скучное 4-байтовое решение (сэкономило 6 байтов благодаря Луису Мендо (забыл правила, касающиеся встроенных функций)):

@det

Объяснение:

Подходит! :)

Стьюи Гриффин
источник
3

TI-Basic, 2 байта

det(Ans

Ах хорошо.

Пожалуйста, не одобряйте тривиальные ответы.

Для старшеклассника (который вынужден владеть одним из этих калькуляторов) эта функция полезна, так что ...

totallyhuman
источник
8
Это все еще полезно в колледже - линейная алгебра не уходит
Тейлор Скотт
5
@TaylorScott На самом деле, он возвращается с местью в дифференциальных уравнениях.
Mego
@Mego - ты прав в этом; хотя по какой-то причине они позволили мне взять все кальки и что до линейного: /
Тейлор Скотт
1
@TaylorScott Из-за контроля со стороны математического факультета моего университета, linalg не был обязательным условием для сравнения, когда я его принимал. Когда мой профессор понял это, он быстро дал нам 3-дневный ускоренный курс по линалгу.
Mego
3

Haskell, 62 байта

a#((b:c):r)=b*d(a++map tail r)-(a++[c])#r
_#_=0
d[]=1
d l=[]#l

Попробуйте онлайн! (Нижний колонтитул с контрольными примерами взят из решения @ totallyhuman.)

dвычисляет определитель, используя разложение Лапласа вдоль первого столбца. Требуется на три байта больше, чем постоянный .

Кристиан Сиверс
источник
3

Python 2 , 95 байт

-12 байт благодаря Линн.

Порт моего Хаскелла ответ .

f=lambda m:sum((-1)**i*v*f([j[:i]+j[i+1:]for j in m[1:]])for i,v in enumerate(m[0]))if m else 1

Попробуйте онлайн!

totallyhuman
источник
1
Здесь тоже можно использовать []в качестве базового варианта: f=lambda m:sum((-1)**i*v*f([j[:i]+j[i+1:]for j in m[1:]])for i,v in enumerate(m[0]))if m else 1за 95 байт!
Линн
m==[]or sum(...)дает 92 байта.
Барботер
3

Wolfram Language (Mathematica) , 53 52 байта

1##&@@@(t=Tuples)@#.Signature/@t[Range@Tr[1^#]&/@#]&

Попробуйте онлайн!

К сожалению, таким образом при вычислении определителя матрицы n на n используется память O ( n n ), что делает недоступными большие тестовые случаи.

Как это работает

Первая часть, 1##&@@@(t=Tuples)@#вычисляет все возможные произведения термина из каждой строки данной матрицы. t[Range@Tr[1^#]&/@#]дает список такой же длины, элементами которого являются такие вещи, как{3,2,1} или{2,2,3} говорящие, какую запись каждой строки мы выбрали для соответствующего продукта.

Мы применяем Signature ко второму списку, который отображает четные перестановки 1, нечетные перестановки -1и неперестановки0 . Это как раз тот коэффициент, с которым соответствующий продукт появляется в определителе.

Наконец, мы берем скалярное произведение двух списков.


Если даже Signatureслишком много встроенного, в 73 байта мы можем взять

1##&@@@(t=Tuples)@#.(1##&@@Order@@@#~Subsets~{2}&/@t[Range@Tr[1^#]&/@#])&

заменить его на 1##&@@Order@@@#~Subsets~{2}&. Это вычисляет Signatureвозможную перестановку, беря произведение Orderпримененного ко всем парам элементов перестановки. Orderдаст, 1если пара находится в порядке возрастания,-1 если она находится в порядке убывания, и 0если они равны.


-1 байт благодаря @ user202729

Миша лавров
источник
1
52 байта (в случае, если вы не знали этот совет по игре в гольф от Mathematica)
user202729
Я сделал, но как-то забыл об этом здесь. Благодарность!
Миша Лавров
3

Python 3 , 238 байтов , 227 байтов , 224 байта , 216 байтов

from functools import*
from itertools import*
r=range;n=len;s=sum
f=lambda l:s(reduce(lambda p,m:p*m,[l[a][b]for a,b in zip(r(n(l)),j)])*(-1)**s(s(y<j[x]for y in j[x:])for x in r(n(l)))for j in permutations(r(n(l))))

Попробуйте онлайн!

Мое решение использует определение определителя для расчетов. К сожалению, сложность этого алгоритма n!и я не могу показать прохождение последнего теста, но в теории это возможно.

Кирилл Малышев
источник
3

CJam ( 50 45 байт)

{:A_,{1$_,,.=1b\)/:CAff*A@zf{\f.*1fb}..-}/;C}

Это анонимный блок (функция), который берет двумерный массив в стек и оставляет целое число в стеке.

Набор онлайн-тестов

рассечение

Это реализует алгоритм Фаддеева-ЛеВерье , и я думаю, что это первый ответ, который выберет такой подход.

Цель состоит в том, чтобы рассчитать коэффициенты сК характеристического полинома N×N матрица A,

п(λ)йе(λяN-A)знак равноΣКзнак равно0NсКλК
где, очевидно, сNзнак равно1 а также с0знак равно(-1)NйеA,

Коэффициенты определяются рекурсивно сверху вниз с помощью вспомогательных матриц. M,

M00сNзнак равно1(Кзнак равно0)MКAMК-1+сN-К+1ясN-Кзнак равно-1КTр(AMК)Кзнак равно1,...,N ,

Код никогда не работает напрямую с сN-К а также MК, но всегда с (-1)КсN-К а также (-1)К+1AMК, поэтому повторение

(-1)КсN-Кзнак равно1КTр((-1)К+1AMК)(-1)К+2AMК+1знак равно(-1)КсN-КA-A((-1)К+1AMК)

{               e# Define a block
  :A            e#   Store the input matrix in A
  _,            e#   Take the length of a copy
  {             e#     for i = 0 to n-1
                e#       Stack: (-1)^{i+2}AM_{i+1} i
    1$_,,.=1b   e#       Calculate tr((-1)^{i+2}AM_{i+1})
    \)/:C       e#       Divide by (i+1) and store in C
    Aff*        e#       Multiply by A
    A@          e#       Push a copy of A, bring (-1)^{i+2}AM_{i+1} to the top
    zf{\f.*1fb} e#       Matrix multiplication
    ..-         e#       Matrix subtraction
  }/
  ;             e#   Pop (-1)^{n+2}AM_{n+1} (which incidentally is 0)
  C             e#   Fetch the last stored value of C
}
Питер Тейлор
источник
2

SageMath , различные

Вот несколько методов вычисления определителя, которые мне показались интересными, все они запрограммированы в SageMath. Их все можно попробовать здесь .

Построение, 3 байта

det

Этот не слишком интересный. Sage предоставляет псевдонимы глобального уровня для многих общих операций, которые обычно являются объектными методами, поэтому это меньше, чем lambda m:m.det().


Действительная часть произведения собственных значений, 36 байт

lambda m:real(prod(m.eigenvalues()))

К сожалению, eigenvaluesэто не один из тех псевдонимов глобального уровня. Это, в сочетании с тем, что у Sage нет аккуратного способа составления функций, означает, что мы застряли на дорогостоящем lambda. Эта функция символьные значения, которые автоматически преобразуются в числовые значения при печати, поэтому некоторые погрешности с плавающей запятой могут присутствовать в некоторых выходных данных.


Произведение диагонали в иорданской нормальной форме, 60 байт

lambda m:prod(m.jordan_form()[x,x]for x in range(m.nrows()))

В иорданской нормальной форме матрица NxN представляется в виде блочной матрицы с N блоками по диагонали. Каждый блок состоит либо из одного собственного значения, либо из матрицы MxM с повторяющимся собственным значением по диагонали и 1s по супердиагональной (диагональ сверху и справа от «главной» диагонали). В результате получается матрица со всеми собственными значениями (с кратностью) на главной диагонали и некоторыми 1s на супердиагональности, соответствующей повторным собственным значениям. Это возвращает произведение диагонали нормальной жордановой формы, которая является произведением собственных значений (с кратностью), так что это более окольный способ выполнения тех же вычислений, что и в предыдущем решении.

Поскольку Сейдж хочет, чтобы нормальная форма Джордана находилась над тем же кольцом, что и исходная матрица, это работает, только если все собственные значения рациональны. Сложные собственные значения приводят к ошибке (если исходная матрица не находится над кольцом CDF(сложные двойные числа с плавающей запятой) или SR). Однако это означает, что брать реальную часть не нужно, по сравнению с вышеупомянутым решением.


Произведение диагонали в разложении Смита

lambda m:prod(m.smith_form()[0].diagonal())

В отличие от нормальной формы Джордана, нормальная форма Смита гарантированно находится над тем же полем, что и исходная матрица. Вместо вычисления собственных значений и представления их с помощью диагональной матрицы блоков, декомпозиция Смита вычисляет элементарные делители матрицы (что является слишком сложной темой для этого поста), помещает их в диагональную матрицу Dи вычисляет две матрицы с единицей. определитель Uи Vтакой, что D = U*A*V(где Aнаходится исходная матрица). Так как определитель произведения матриц равен произведению определителей матриц ( det(A*B*...) = det(A)*det(B)*...), а также Uи Vопределены имеющими единичные детерминанты, det(D) = det(A). Определитель диагональной матрицы - это просто произведение элементов на диагонали.

Расширение Лапласа, 109 байт

lambda m:m.nrows()>1and sum((-1)**j*m[0,j]*L(m[1:,:j].augment(m[1:,j+1:]))for j in range(m.ncols()))or m[0,0]

Это выполняет расширение Лапласа вдоль первого ряда, используя рекурсивный подход. det([[a]]) = aиспользуется для базового случая. Это должно быть короче, чтобы использовать det([[]]) = 1для базового случая, но моя попытка в этой реализации имела ошибку, которую я еще не смог отследить.


Формула Лейбница, 100 байтов

L2 = lambda m:sum(sgn(p)*prod(m[k,p[k]-1]for k in range(m.ncols()))for p in Permutations(m.ncols()))

Это непосредственно реализует формулу Лейбница. Чтобы получить лучшее объяснение формулы и почему она работает, чем я мог бы написать, посмотрите этот превосходный ответ .


Реальная часть e^(Tr(ln(M))), 48 байтов

lambda m:real(exp(sum(map(ln,m.eigenvalues()))))

Эта функция возвращает символические выражения. Чтобы получить числовое приближение, позвоните n(result)перед печатью.

Это подход, который я еще никому не видел. Я собираюсь дать более подробное объяснение этому.

Позвольте Aбыть квадратной матрицы над реалами. По определению определитель Aравен произведению собственных значений A. След Aравен сумме Aсобственных значений. Для действительных чисел r_1и r_2, exp(r_1) * exp(r_2) = exp(r_1 + r_2). Поскольку матричная экспоненциальная функция определена как аналог скалярной экспоненциальной функции (особенно в предыдущем тождестве), а матричная экспонента может быть вычислена путем диагонализации матрицы и применения скалярной экспоненциальной функции к собственным значениям на диагонали, мы можем сказать, det(exp(A)) = exp(trace(A))(продукт exp(λ)для каждого собственного значения λиз Aравна сумме собственных значений .exp(A) ). Таким образом, если мы можем найти матрицу , мы можем вычислитьL , чтоexp(L) = Adet(A) = exp(trace(L))

Мы можем найти такую ​​матрицу с Lпомощью вычислений log(A). Матричный логарифм может быть вычислен так же, как матрица экспоненциальная: сформируйте квадратную диагональную матрицу, применив скалярную функцию логарифма к каждому собственному значению A(именно поэтому мы ограничены действительными значениями A). Поскольку мы заботимся только о следе L, мы можем пропустить построение и просто напрямую суммировать экспоненты собственных значений. Собственные значения могут быть комплексными, даже если матрица не находится над комплексным кольцом, поэтому мы берем действительную часть суммы.

Мего
источник
1
Последняя часть - захватывающая идея, но заголовок и объяснение не соответствуют коду, который не принимает матричный логарифм. Это просто без real(prod(m.eigenvalues()))присмотра.
Питер Тейлор
2

Java 8, 266 261 259 258 байт

long d(int[][]m){long r=0;int i=0,j,k,l=m.length,t[][]=new int[l-1][l-1],q=m[0][0];if(l<3)return l<2?q:q*m[1][1]-m[0][1]*m[1][0];for(;i<l;r+=m[0][i]*(1-i++%2*2)*d(t))for(j=0;++j<l;)for(k=l;k-->0;){q=m[j][k];if(k<i)t[j-1][k]=q;if(k>i)t[j-1][k-1]=q;}return r;}

Послушай, мама, без встроенных модулей .. потому что у Java их нет ..>.>

-7 байт благодаря @ceilingcat .

Объяснение:

Попробуй это здесь. (Только последний контрольный пример слишком велик для longразмера 2 63 -1.)

long d(int[][]m){             // Method with integer-matrix parameter and long return-type
  long r=0;                   //  Return-long, starting at 0
  int i=0,j,k,                //  Index-integers
      l=m.length,             //  Dimensions of the square matrix
      t[][]=new int[l-1][l-1],//  Temp-matrix, one size smaller than `m`
      q=m[0][0];              //  The first value in the matrix (to reduce bytes)
  if(l<3)                     //  If the dimensions are 1 or 2:
    return l<2?               //   If the dimensions are 1:
      q                       //    Simply return the only item in it
     :                        //   Else (the dimensions are 2):
      q*m[1][1]-m[0][1]*m[1][0];
                              //    Calculate the determinant of the 2x2 matrix
                              //  If the dimensions are 3 or larger: 
  for(;i<l;                   //  Loop (1) from 0 to `l` (exclusive)
      r+=                     //    After every iteration: add the following to the result:
         m[0][i]              //     The item in the first row and `i`'th column,
         *(1-i++%2*2)         //     multiplied by 1 if `i` is even; -1 if odd,
         *d(t))               //     multiplied by a recursive call with the temp-matrix
    for(j=0;                  //   Reset index `j` to 0
        ++j<l;)               //   Inner loop (2) from 0 to `l` (exclusive)
      for(k=l;k-->0;){        //    Inner loop (3) from `l-1` to 0 (inclusive)
        q=m[j][k];            //     Set the integer at location `j,k` to reduce bytes
        if(k<i)               //     If `k` is smaller than `i`:
          t[j-1][k]=q;        //      Set this integer at location `j-1,k`
        if(k>i)               //     Else-if `k` is larger than `i`:
          t[j-1][k-1]=q;      //      Set this integer at location `j-1,k-1`
                              //     Else: `k` and `i` are equals: do nothing (implicit)
      }                       //    End of inner loop (3)
                              //   End of inner loop (2) (implicit / single-line body)
                              //  End of loop (1) (implicit / single-line body)
  return r;                   //  Return the result-long
}                             // End of method
Кевин Круйссен
источник
2

JavaScript (ES6), 91

Рекурсивный Лаплас

q=(a,s=1)=>+a||a.reduce((v,[r],i)=>v-(s=-s)*r*q(a.map(r=>r.slice(1)).filter((r,j)=>j-i)),0)

Меньше гольфа

q = (a,s=1) => // s used as a local variable
  a[1] // check if a is a single element array 
       // if array, recursive call expanding along 1st column
  ? a.reduce((v,[r],i) => v-(s=-s)*r*q(a.map(r=>r.slice(1)).filter((r,j)=>j-i)),0) 
  : +a // single element, convert to number

Тест

q=(a,s=1)=>+a||a.reduce((v,[r],i)=>v-(s=-s)*r*q(a.map(r=>r.slice(1)).filter((r,j)=>j-i)),0)

TestCases=`[[42]] -> 42
[[2, 3], [1, 4]] -> 5
[[1, 2, 3], [4, 5, 6], [7, 8, 9]] -> 0
[[13, 17, 24], [19, 1, 3], [-5, 4, 0]] -> 1533
[[372, -152, 244], [-97, -191, 185], [-53, -397, -126]] -> 46548380
[[100, -200, 58, 4], [1, -90, -55, -165], [-67, -83, 239, 182], [238, -283, 384, 392]] -> 571026450
[[432, 45, 330, 284, 276], [-492, 497, 133, -289, -28], [-443, -400, 56, 150, -316], [-344, 316, 92, 205, 104], [277, 307, -464, 244, -422]] -> -51446016699154`
.split('\n')

TestCases.forEach(r=>{
  [a,k] = r.split (' -> ')
  a = eval(a)
  d = q(a)
  console.log('Test '+(k==d ? 'OK':'KO')+
    '\nMatrix '+a.join('|')+
    '\nResult '+d+
    '\nCheck  '+k)
})

edc65
источник
83 байта с таким же поведением
Арно
Или 85 байтов для поддержки пустой матрицы (определитель которой должен быть 1 ).
Арно
(Я использовал те же оптимизации в этом ответе , который получен из вашего.)
Арно
1

Java (OpenJDK 8) , 195 192 177 байт

long d(int[][]m){long D=0;for(int l=m.length-1,t[][]=new int[l][l],i=0,j,k;i<=l;D+=m[0][i]*(1-i++%2*2)*(l<1?1:d(t)))for(j=0;j<l*l;)t[j/l][k=j%l]=m[1+j++/l][k<i?k:k+1];return D;}

Попробуйте онлайн!

Как и многие другие ответы, здесь также используется формула Лапласа. Чуть менее гольф-версия:

long d(int[][]m){
  long D=0;
  int l=m.length-1,t[][]=new int[l][l],i=0,j,k;
  for(;i<=l;)
    for(j=0;j<l*l;)
      t[j/l][k=j%l]=m[1+j++/l][k<i?k:k+1];
    D+=m[0][i]*(1-i++%2*2)*(l<1?1:d(t));
  return D;
}
ceilingcat
источник