Determinante de uma matriz inteira

34

Dada uma matriz inteira quadrada como entrada, produza o determinante da matriz.

Regras

  • Você pode supor que todos os elementos da matriz, o determinante da matriz e o número total de elementos na matriz estejam dentro do intervalo representável de números inteiros para o seu idioma.
  • É permitido emitir um valor decimal / flutuante com uma parte fracionária de 0 (por exemplo, em 42.0vez de 42).
  • Builtins são permitidos, mas você deve incluir uma solução que não use os builtins.

Casos de teste

[[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
Mego
fonte
existe um tamanho máximo de matriz que precisa ser suportado ou é arbitrário?
Taylor Scott
1
@TaylorScott Primeira regra listada: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.
Mego
4
Você sabe que tem um desafio interessante quando você tem 4 Jelly responde consecutivamente out-golfe uns aos outros ...
totallyhuman

Respostas:

25

Gelatina , 15 bytes

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

Experimente online!

Como funciona

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

Por que funciona - versão mathy

O operador det pega uma matriz e retorna um escalar. Um n -by- n matriz pode ser pensado como um conjunto de n vetores de tamanho n , então det é realmente uma função que toma n vetores de ℤ n e retorna um escalar.

Portanto, escrevo det ( v 1 , v 2 , v 3 , ..., v n ) para det [ v 1 v 2 v 3 ... v n ].

Observe que det é linear em cada argumento, ou seja, 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 ). Portanto, é um mapa linear de (ℤ n ) n para ℤ.

Basta determinar a imagem da base no mapa linear. A base de (ℤ n ) n consiste em produtos tensores n vezes os elementos base de ℤ n , ieeg 5 e 3 e 3 e 1 e 5 e 1 . Os produtos tensores que incluem tensores idênticos devem ser enviados a zero, pois o determinante de uma matriz na qual duas colunas são idênticas é zero. Resta verificar para onde são enviados os produtos tensores de elementos básicos distintos. Os índices dos vetores no produto tensorial formam uma bijeção, isto é, uma permutação, na qual permutações pares são enviadas para 1 e permutações ímpares são enviadas para -1.

Por exemplo, para encontrar o determinante de [[1, 2], [3, 4]]: observe que as colunas são [1, 3] e [2, 4]. Nós decompomos [1, 3] para dar (1 e 1 + 3 e 2 ) e (2 e 1 + 4 e 2 ). O elemento correspondente no produto tensorial é (1 e 1 ⊗ 2 e 1 + 1 e 1 ⊗ 4 e 2 + 3 e 2 ⊗ 2 e 1 + 3 e 2 ⊗ 4 e 2 ), que simplificamos para (2 e 1 ⊗ e 1 + 4 e 1 ⊗ e 2 + 6 e 2 ⊗ e 1 + 12 e 2 ⊗ e dois) Assim sendo:

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

Agora resta provar que a fórmula para encontrar a paridade da permutação é válida. O que meu código faz é encontrar essencialmente o número de inversões, ou seja, os lugares onde um elemento à esquerda é maior que um elemento à direita (não necessariamente consecutivamente).

Por exemplo, na permutação 3614572, existem 9 inversões (31, 32, 61, 64, 65, 62, 42, 52, 72), portanto a permutação é ímpar.

A justificativa é que cada transposição (troca de dois elementos) adiciona uma inversão ou retira uma inversão, trocando a paridade do número de inversões, e a paridade da permutação é a paridade do número de transposições necessárias para obter a permutação.

Portanto, em conclusão, nossa fórmula é dada por:

Por que funciona - versão não matemática

onde σ é uma permutação de 𝕊 n o grupo de todas as permutações de n letras, e SGN é o sinal da permutação, AKA (-1) levantada para a paridade da permutação, e um i j é o ( ij ) th entrada em a matriz ( i abaixo, j transversalmente).

Freira Furada
fonte
17
Essa "versão não matemática" é bastante matemática.
MD XF
6
As fórmulas e símbolos e números do @MDXF dificilmente constituem matemática. A matemática é a abstração, a generalização e a lógica por trás das manipulações formais dos símbolos.
Leaky Nun
7
O @JAB Jelly implementa sua própria página de códigos personalizada . (Um destes dias, TIO vai incluir um link para a página de código ...)
totallyhuman
1
@Mego, a "soma dos produtos na diagonal" funciona apenas para matrizes 1x1, 2x2 e 3x3. Para matrizes maiores, é necessário considerar todas as permutações e sua paridade.
Freira vazada
3
+1 para realmente incluir a prova na postagem em vez de dizer "porque esta fórmula está listada na página abcxyz, deve ser verdadeira".
user202729
11

R , 3 bytes

Solução trivial

det

Experimente online!

R , 94 92 bytes

solução reimplementada

superado por Jarko Dubbeldam

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

Experimente online!

Recursivamente usa a expansão por menores na primeira coluna da matriz.

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
fonte
32 bytes
JAD 11/11
9

Gelatina , 16 15 12 10 bytes

Ḣ×Zß-Ƥ$Ṛḅ-

Usa a expansão Laplace . Graças a @miles por jogar fora 3 5 bytes!

Experimente online!

Como funciona

Ḣ×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.
Dennis
fonte
8

Wolfram Language (Mathematica) , entre 14 e 42 bytes

Tivemos uma solução integrada de 3 bytes e uma solução de 53 bytes que evitam completamente os embutidos; portanto, aqui estão algumas soluções mais estranhas em algum lugar.

A Wolfram Language possui muitas funções muito intensas para decompor matrizes em produtos de outras matrizes com estrutura mais simples. Um dos mais simples (ou seja, eu já ouvi isso antes) é a decomposição da Jordânia. Toda matriz é semelhante a uma matriz triangular superior (possivelmente com valor complexo) feita de blocos diagonais com uma estrutura específica, chamada decomposição de Jordan dessa matriz. A similaridade preserva os determinantes, e o determinante de uma matriz triangular é o produto dos elementos diagonais, para que possamos calcular o determinante com os seguintes 42 bytes :

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

O determinante também é igual ao produto dos autovalores de uma matriz, com multiplicidade. Felizmente, a função de autovalor do Wolfram controla a multiplicidade (mesmo para matrizes não diagonalizáveis), para obter a seguinte solução de 20 bytes :

1##&@@Eigenvalues@#&

A próxima solução é meio que trapacear e não sei ao certo por que funciona. O Wronskiano de uma lista de n funções é o determinante da matriz das primeiras derivadas n -1 das funções. Se atribuirmos à Wronskianfunção uma matriz de números inteiros e dissermos que a variável de diferenciação é 1, de alguma forma ela cospe o determinante da matriz. É estranho, mas não envolve as letras " Det" e tem apenas 14 bytes

#~Wronskian~1&

(O determinante Casoratian funciona tão bem, para mais um byte: #~Casoratian~1&)

No domínio da álgebra resumo, o determinante de um n  x  n matriz (pensado como o mapa k → k que é a multiplicação pelo determinante) é o n ° de energia exterior da matriz (após a colheita um isomorfismo k → ⋀ n k n ) Na linguagem Wolfram, podemos fazer isso com os seguintes 26 bytes :

HodgeDual[TensorWedge@@#]&

E aqui está uma solução que funciona apenas para determinantes positivos. Se pegarmos um hipercubo de unidade n- dimensional e aplicarmos uma transformação linear a ele, o "volume" n- dimensional da região resultante é o valor absoluto do determinante da transformação. A aplicação de uma transformação linear a um cubo fornece um paralelepípedo, e podemos obter seu volume com os seguintes 39 bytes de código:

RegionMeasure@Parallelepiped[Last@#,#]&
Não é uma árvore
fonte
1
A solução que tive nesse sentido foi Exp@*Tr@*MatrixLog, mas infelizmente isso não funciona para matrizes singulares.
Misha Lavrov
1
@MishaLavrov Ooh, isso é inteligente! Eu acho que você pode consertar isso Check[E^Tr@MatrixLog@#,0]&.
Não uma árvore
Isso é ótimo! Eu não tinha conhecimento Checkantes.
Misha Lavrov
1
Eu criei um desafio para a Jordan Decomposition há um tempo atrás. Você pode estar interessado também. Que ótima resposta!
Mego
8

Haskell , 71 bytes

-3 bytes graças a Lynn. Outro bytes a poeira, graças a Craig Roy.

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

Experimente online! Adicionado -Osinalizador para fins de otimização. Não é necessário.

Explicação (desatualizada)

f implementa recursivamente a expansão do cofator.

f[[x]]=x

Esta linha abrange o caso de uma base de 1 x 1 matriz, no caso em que o determinante é mat[0, 0].

f(h:t)=

Isso usa a correspondência de padrões de Haskell para quebrar a matriz em uma cabeça (a primeira linha) e uma cauda (o resto da matriz).

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

Enumere a cabeça da matriz (fechando a lista infinita de números inteiros e a cabeça) e itere sobre ela.

           (-1)*i*v

Negue o resultado com base no fato de seu índice ser uniforme, pois o cálculo do determinante envolve adição e subtração alternadas.

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

Isso essencialmente remove a i - ésima coluna da cauda, ​​pegando elementos i e concatenando-a com a linha com os primeiros (i + 1) th elementos descartados para cada linha na cauda.

                   *f

Calcule o determinante do resultado acima e multiplique pelo resultado de (-1)*i*v.

       sum

Soma o resultado da lista acima e devolva-o.

totalmente humano
fonte
2
você poderia economizar 1 byte se substituir o sum[(-1)^i*...comfoldr(-)0[...
Craig Roy
6

Próton , 99 bytes

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)

Experimente online!

-3 bytes graças ao Sr. Xcoder
-3 bytes graças a Erik, o Outgolfer

Expansão na primeira linha

HyperNeutrino
fonte
Só porque Proton não tem construído para determinante.
user202729
103 bytes . ((~i%2)*2-1)->((-i%2)|1)
Sr. Xcoder
Também 102 bytes substituindo j!=ipor j-iou i-j.
Mr. Xcoder
99 bytes
Erik the Outgolfer
@EriktheOutgolfer Ah sim, obrigado!
HyperNeutrino
5

Oitava , 28 bytes

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

Experimente online!

Isto usa a decomposição de QR de uma matriz X em uma matriz orthgonal Q e uma matriz triangular superior R . O determinante de X é o produto de aqueles de Q e R . Uma matriz ortogonal tem determinante de unidade e, para uma matriz triangular, o determinante é o produto de suas entradas diagonais. De Octave qrfunção chamada com uma única saída dá R .

O resultado é arredondado para o número inteiro mais próximo. Para matrizes de entrada grandes, imprecisões de ponto flutuante podem produzir um erro excedente 0.5e, portanto, produzir um resultado errado.

Luis Mendo
fonte
1
Essa é uma maneira interessante de fugir do que está detembutido. ;)
tomsmeding
1
@tomsmeding :-) Além disso, ele já havia sido "usado" na resposta de Stewie
Luis Mendo
5

Haskell , 59 bytes

p%(l:r)=l!!0*f(tail<$>p++r)-(p++[l])%r
[]%_=1
p%_=0
f=([]%)

Experimente online!

xnor
fonte
5

C,  176  125 bytes

Obrigado a @ceilingcat por jogar 42 bytes de golfe e obrigado a @Lynn e @Jonathan Frech por salvar um byte cada!

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

Calcula o determinante usando a expansão Laplace ao longo da primeira linha.

Experimente online!

Desenrolado:

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
fonte
(i%2*-2+1)(1-i%2*2)salva mais um byte.
Lynn
n+1+cpode ser n-~c.
Jonathan Frech
Sugerir em i=svez dereturn s
ceilingcat 25/11
5

Gelatina , 43 bytes

Finalmente, escrevi minha solução não integrada em um idioma de golfe!

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

Agradecemos ao HyperNeutrino por salvar um byte!

Experimente online! (código espaçado para maior clareza)

terrivelmente longo para remover os enésimos elementos de uma lista, melhorará mais tarde


Essa resposta foi superada pelas respostas de HyperNeutrino, Dennis e Leaky Nun. A geléia é muito popular como idioma de golfe.

Explicação rápida:

ÇḢḢ$Ṗ?    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
fonte
4

Gelatina , 24 bytes

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

Experimente online!

Explicação

œ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 bytes graças à solução de user202729

HyperNeutrino
fonte
4

MATL , 3 bytes / 5 bytes

Com função embutida

&0|

Experimente online!

Sem embutido

Obrigado a Misha Lavrov por apontar um erro, agora corrigido

YvpYo

Experimente online!

Isso calcula o determinante como o produto dos autovalores, arredondado para o número inteiro mais próximo para evitar imprecisões de ponto flutuante.

Yv       % Implicit input. Push vector containing the eigenvalues
p        % Product
Yo       % Round. Implicit display
Luis Mendo
fonte
O produto dos valores singulares não informaria apenas o valor absoluto do determinante?
Misha Lavrov
@MishaLavrov Você está totalmente certo! Obrigado por perceber. Eu corrigi-lo usando valores próprios em vez de valores singulares ... e que salva 4 bytes \ o /
Luis Mendo
4

R , 32 bytes

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

Não utiliza o algoritmo de uma árvore para obter os autovalores da matriz e a parte real de seu produto.

Experimente online!

JAD
fonte
Muito elegante! +1.
11137 Giuseppe
3

Oitava , 30 bytes

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

Experimente online!

ou, a chata solução de 4 bytes (economizou 6 bytes graças a Luis Mendo (esqueceu as regras relativas às funções internas)):

@det

Explicação:

Chegando! :)

Stewie Griffin
fonte
3

TI-Basic, 2 bytes

det(Ans

Ah bem.

Por favor, não vote em respostas triviais.

Como um estudante do ensino médio (que é forçado a possuir uma dessas calculadoras), essa função é muito útil, então ...

totalmente humano
fonte
8
É ainda hella útil na faculdade - álgebra linear não vai embora
Taylor Scott
5
@TaylorScott De fato, ele volta com uma vingança em equações diferenciais.
Mego
@Mego - você está certo nisso; embora por alguma razão eles me permitam calcular todo o cálculo e isso antes do linear: /
Taylor Scott
1
@TaylorScott Devido a uma supervisão do departamento de matemática da minha universidade, linalg não era um pré-requisito para a diffeq quando a tirei. Quando meu professor percebeu isso, ele rapidamente nos deu um curso intensivo de três dias em linalg.
Mego
3

Haskell, 62 bytes

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

Experimente online! (Rodapé com casos de teste retirados da solução do totallyhuman.)

dcalcula o determinante usando uma expansão de Laplace ao longo da primeira coluna. Precisa de três bytes a mais que o permanente .

Peneiradores cristãos
fonte
3

Python 2 , 95 bytes

-12 bytes graças a Lynn.

Porto da minha resposta Haskell .

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

Experimente online!

totalmente humano
fonte
1
Aqui também você pode usar []como caso base: 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 1para 95 bytes!
Lynn
m==[]or sum(...)92 bytes.
quer
3

Wolfram Language (Mathematica) , 53 52 bytes

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

Experimente online!

Infelizmente, computar o determinante de um n por n matriz desta forma usos O ( N n ) de memória, o que coloca grandes casos de teste fora do alcance.

Como funciona

A primeira parte 1##&@@@(t=Tuples)@#,, calcula todos os produtos possíveis de um termo de cada linha da matriz especificada. t[Range@Tr[1^#]&/@#]dá uma lista do mesmo comprimento cujos elementos são coisas como {3,2,1}ou {2,2,3}dizendo que a entrada de cada linha que escolheu para o produto correspondente.

Aplicamos Signaturea segunda lista, que mapeia permutações pares para 1, permutações ímpares para -1e não permutações para 0. Este é precisamente o coeficiente com o qual o produto correspondente aparece no determinante.

Finalmente, pegamos o produto escalar das duas listas.


Se even Signaturefor muito embutido, com 73 bytes , podemos obter

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

substituindo-o por 1##&@@Order@@@#~Subsets~{2}&. Isso calcula Signatureuma permutação possível, tomando o produto de Orderaplicado a todos os pares de elementos da permutação. Orderdará 1se o par estiver em ordem crescente, -1se estiver em ordem decrescente e 0se forem iguais.


-1 byte graças a @ user202729

Misha Lavrov
fonte
1
52 bytes (caso você não conheça essa dica de golfe do Mathematica) #
user202729 11/11
Eu fiz, mas de alguma forma esqueci aqui. Obrigado!
Misha Lavrov
3

Python 3 , 238 bytes , 227 bytes , 224 bytes , 216 bytes

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

Experimente online!

Minha solução usa a definição de um determinante para cálculos. Infelizmente, a complexidade desse algoritmo é n!e não posso mostrar a passagem do último teste, mas, em teoria, isso é possível.

Кирилл Малышев
fonte
3

CJam ( 50 45 bytes)

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

Este é um bloco anônimo (função) que pega uma matriz 2D na pilha e deixa um número inteiro na pilha.

Conjunto de testes online

Dissecação

Isso implementa o algoritmo de Faddeev-LeVerrier , e acho que é a primeira resposta para essa abordagem.

ckn×nA

p(λ)det(λInA)=k=0nckλk
cn=1c0=(1)ndetA

M

M00cn=1(k=0)MkAMk1+cnk+1Icnk=1ktr(AMk)k=1,,n .

cnkMk(1)kcnk(1)k+1AMk

(1)kcnk=1ktr((1)k+1AMk)(1)k+2AMk+1=(1)kcnkAA((1)k+1AMk)

{               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
}
Peter Taylor
fonte
2

Python 2 , 75 bytes

f=lambda m,p=[]:m[0][0]*f(zip(*p+m[1:])[1:])-f(m[1:],p+m[:1])if m else[]==p

Experimente online!

xnor
fonte
2

SageMath , vários

Aqui estão alguns métodos para calcular o determinante que achei interessante, todos programados no SageMath. Todos eles podem ser experimentados aqui .

Incorporado, 3 bytes

det

Este não é muito interessante. O Sage fornece aliases em nível global para muitas operações comuns que normalmente seriam métodos de objeto, então isso é mais curto que lambda m:m.det().


Parte real do produto de valores próprios, 36 bytes

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

Infelizmente, eigenvaluesnão é um desses aliases em nível global. Isso, combinado com o fato de o Sage não ter uma maneira elegante de compor funções, significa que estamos presos a um custo alto lambda. Os valores simbólicos desta função que são convertidos automaticamente em valores numéricos quando impressos, portanto, algumas imprecisões de ponto flutuante podem estar presentes em algumas saídas.


Produto da Diagonal na Forma Normal da Jordânia, 60 bytes

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

Na forma Jordan Normal, uma matriz NxN é representada como uma matriz de blocos, com N blocos na diagonal. Cada bloco consiste em um único valor próprio ou em uma matriz MxM com um valor próprio repetido na diagonal 1es na super diagonal (a diagonal acima e à direita da diagonal "principal"). Isso resulta em uma matriz com todos os autovalores (com multiplicidade) na diagonal principal e alguns 1s na super diagonal correspondendo a autovalores repetidos. Isso retorna o produto da diagonal da forma normal de Jordan, que é o produto dos autovalores (com multiplicidade), portanto, essa é uma maneira mais indireta de executar o mesmo cálculo da solução anterior.

Como Sage deseja que a forma normal de Jordan esteja no mesmo anel que a matriz original, isso só funciona se todos os autovalores forem racionais. Autovalores complexos resultam em um erro (a menos que a matriz original esteja acima do anel CDF(flutuadores duplos complexos) ou SR). No entanto, isso significa que não é necessário assumir a parte real, em comparação com a solução acima.


Produto da Diagonal na Decomposição de Smith

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

Diferentemente da forma normal da Jordan, é garantido que a forma normal de Smith esteja no mesmo campo da matriz original. Em vez de calcular os autovalores e representá-los com uma matriz diagonal de bloco, a decomposição de Smith calcula os divisores elementares da matriz (que é um tópico um pouco complicado demais para este post), os coloca em uma matriz diagonal De calcula duas matrizes com unidade determinante Ue Vtal que D = U*A*V(onde Aestá a matriz original). Como o determinante do produto de matrizes é igual ao produto dos determinantes das matrizes ( det(A*B*...) = det(A)*det(B)*...) Ue Vé definido como tendo determinantes de unidade det(D) = det(A),. O determinante de uma matriz diagonal é simplesmente o produto dos elementos na diagonal.

Expansão de Laplace, 109 bytes

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]

Isso realiza a expansão de Laplace ao longo da primeira linha, usando uma abordagem recursiva. det([[a]]) = aé usado para o caso base. Deve ser mais curto para usar det([[]]) = 1no caso base, mas minha tentativa nessa implementação teve um erro que ainda não consegui rastrear.


Fórmula de Leibniz, 100 bytes

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

Isso implementa diretamente a fórmula de Leibniz. Para uma explicação muito melhor da fórmula e por que ela funciona do que eu poderia escrever, veja esta excelente resposta .


Parte real de e^(Tr(ln(M))), 48 bytes

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

Esta função retorna expressões simbólicas. Para obter uma aproximação numérica, ligue n(result)antes da impressão.

Essa é uma abordagem que ainda não vi ninguém usar. Vou dar uma explicação mais longa e detalhada para este.

Seja Auma matriz quadrada sobre os reais. Por definição, o determinante de Aé igual ao produto dos valores próprios de A. O traço de Aé igual à soma dos Aautovalores de s. Para números reais r_1e r_2, exp(r_1) * exp(r_2) = exp(r_1 + r_2). Como a função exponencial da matriz é definida como análoga à função exponencial escalar (especialmente na identidade anterior), e a exponencial da matriz pode ser calculada diagonalizando a matriz e aplicando a função exponencial escalar aos valores próprios na diagonal, podemos dizer det(exp(A)) = exp(trace(A))(o produto de exp(λ)para cada valor próprio λde Aé igual à soma dos valores próprios de exp(A)). Assim, se pudermos encontrar uma matriz Ltal queexp(L) = A, podemos calcular det(A) = exp(trace(L)).

Podemos encontrar essa matriz Latravés da computação log(A). O logaritmo da matriz pode ser calculado da mesma maneira que o exponencial da matriz: forme uma matriz diagonal quadrada aplicando a função de logaritmo escalar a cada autovalor de A(é por isso que restringimos Aos reais). Como nos preocupamos apenas com o rastreio de L, podemos pular a construção e somar diretamente os exponenciais dos valores próprios. Os valores próprios podem ser complexos, mesmo que a matriz não esteja acima do anel complexo, portanto, pegamos a parte real da soma.

Mego
fonte
1
A última parte é uma ideia fascinante, mas o cabeçalho e a explicação não correspondem ao código, o que não requer um logaritmo da matriz. É simplesmente não- real(prod(m.eigenvalues()))destruído.
Peter Taylor
2

Java 8, 266 261 259 258 bytes

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

Olha mãe, sem build-ins .. porque o Java não tem ..>.>

-7 bytes graças a @ceilingcat .

Explicação:

Experimente aqui. (Apenas o último caso de teste é muito grande para caber em um longtamanho 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
Kevin Cruijssen
fonte
2

JavaScript (ES6), 91

Laplace recursivo

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)

Menos golfe

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

Teste

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
fonte
83 bytes com o mesmo comportamento
Arnauld 14/11
Ou 85 bytes para suportar a matriz vazia (cujo determinante deve ser 1 ).
Arnauld
(Eu usei as mesmas otimizações em esta resposta , a qual é derivada da sua.)
Arnauld
1

Java (OpenJDK 8) , 195 192 177 bytes

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

Experimente online!

Como muitas outras respostas, isso também usa a fórmula de Laplace. Uma versão um pouco menos golfe:

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;
}
teto
fonte