Trigonometria matricial

13

Introdução

As duas funções trigonométricas mais comuns, sinee cosine(ou sine cospara abreviar), pode ser estendida a ser valorizado funções de matriz. Uma maneira de calcular os análogos com valor de matriz é a seguinte:

Considere estas duas identidades trigonométricas importantes:

identidades trigonométricas

Usando essas identidades, podemos derivar as seguintes equações para sine cos:

funções trigonométricas

A exponencial da matriz existe para todas as matrizes quadradas e é dada por:

matriz exponencial

onde A 0 representa a matriz identidade I com as mesmas dimensões que um . Usando a matriz exponencial, essas duas funções trigonométricas (e, portanto, todas as outras funções trigonométricas) podem ser avaliadas como funções de matrizes.

O desafio

Dada uma matriz quadrada A , produza os valores de sin(A)e cos(A).

Regras

  • A entrada e a saída podem estar em qualquer formato conveniente e razoável (matriz 2D, formato de matriz do seu idioma etc.).
  • Você pode escrever um único programa, dois programas independentes, uma única função ou duas funções. Se você optar por escrever duas funções, o código poderá ser compartilhado entre elas (como importações e funções auxiliares).
  • Os valores da matriz de entrada sempre serão inteiros.
  • Sua solução pode ter problemas de precisão como resultado de imprecisão de ponto flutuante. Se o seu idioma possui valores mágicos de precisão infinita, sua solução deve funcionar perfeitamente (ignorando o fato de que isso exigiria tempo e / ou memória infinitos). No entanto, como esses valores mágicos de precisão infinita não existem, imprecisões causadas por precisão limitada são aceitáveis. Esta regra está em vigor para evitar complicações resultantes da exigência de uma quantidade específica de precisão na saída.
  • Construções que calculam funções trigonométricas para argumentos de matriz (incluindo funções trigonométricas hiperbólicas) não são permitidas. Outras construções internas da matriz (como multiplicação, exponenciação, diagonalização, decomposição e exponencial da matriz) são permitidas.

Casos de teste

Formato: A -> sin(A), cos(A)

[[0]] -> [[0]], [[1]]
[[0, 2], [3, 5]] -> [[-0.761177343863758, 0.160587281888277], [0.240880922832416, -0.359709139143065]], [[0.600283445979886, 0.119962280223493], [0.179943420335240, 0.900189146538619]]
[[1, 0, 1], [0, 0, 0], [0, 1, 0]] -> [[0.841470984807897, -0.158529015192103, 0.841470984807897], [0, 0, 0], [0, 1, 0]], [[0.540302305868140, -0.459697694131860, -0.459697694131860], [0, 1, 0], [0, 0, 1]]
[[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]] -> [[0.841470984807897, 0, 0, 0, 0], [0, 0.841470984807897, 0, 0, 0], [0, 0, 0.841470984807897, 0, 0], [0, 0, 0, 0.841470984807897, 0], [0, 0, 0, 0, 0.841470984807897]], [[0.540302305868140, 0, 0, 0, 0], [0, 0.540302305868140, 0, 0, 0], [0, 0, 0.540302305868140, 0, 0], [0, 0, 0, 0.540302305868140, 0], [0, 0, 0, 0, 0.540302305868140]]
[[-3, 2, -6], [3, 0, 4], [4, -2, 7]] -> [[-0.374786510963954, 0.135652884035570, -1.35191037980742], [1.14843105375406, 0.773644542790111, 1.21625749577185], [1.21625749577185, -0.135652884035570, 2.19338136461532]], [[4.13614256031450, -1.91289828483056, 5.50873853927692], [-2.63939111203107, 1.49675144828342, -3.59584025444636], [-3.59584025444636, 1.91289828483056, -4.96843623340878]]

Leitura adicional

Esta excelente pergunta sobre Math.SE inclui algumas derivações alternativas dos análogos com valor matricial das funções trigonométricas.

Mego
fonte
Eu fiquei sin([[1, 0, 1], [0, 0, 0], [0, 1, 0]]) = {{0.841, -0.158, 0.841}, {0, 0, 0}, {0, 1, 0}}com o Mathematica, você pode conferir?
Kennytm
1
@kennytm É isso que o caso de teste mostra.
Mego 5/05
1
@Mego Aparentemente, todas as respostas existentes devem ser excluídas.
feersum 5/05
3
@Mego É completamente irracional pensar que todos os componentes internos de ponto flutuante usam um algoritmo exato (ou um que seria exato se as operações de ponto flutuante fossem substituídas por operações com "número real").
Feersum 5/05
1
@feersum Abordei isso na minha edição mais recente:(ignoring the fact that it would require infinite time and/or memory)
Mego

Respostas:

6

Julia, 33 19 bytes

A->reim(expm(A*im))

Esta é uma função que aceita uma matriz bidimensional de flutuadores e retorna uma tupla de tais matrizes correspondentes ao cosseno e seno, respectivamente. Observe que isso é o inverso da ordem dada nos casos de teste, nos quais o seno é listado primeiro.

Para uma matriz A de valor real , temos

seno

e

cosseno

Ou seja, o seno e cosseno de A correspondem às partes imaginárias e reais da matriz exponencial e iA . Veja Funções de matrizes (Higham, 2008).

Experimente online! (inclui todos os casos de teste)

Economizou 14 bytes graças a Dennis!

Alex A.
fonte
6

Mathematica, 27 bytes

{Im@#,Re@#}&@MatrixExp[I#]&

Baseado na solução de @ Rainer P ..

Pega a matriz quadrada Acomo argumento e gera uma lista contendo {sin(A), cos(A)}.

A entrada é formatada com Npara obter um valor numérico em vez de uma fórmula exata longa e Columnexibir os resultados de sin(A)e cos(A)como matrizes separadas em vez de uma lista aninhada.

Exemplo

Calcular os valores separadamente requer 38 bytes

{(#2-#)I,+##}/2&@@MatrixExp/@{I#,-I#}&
milhas
fonte
6

Geléia , 23 22 bytes

³æ*÷!
®Ḥ‘©r0Ç€s2_@/µÐL

Experimente online!

fundo

Essa abordagem calcula diretamente a série de Taylor para seno e cosseno , ou seja,

Fórmula

Ele aumenta o número de termos iniciais de ambas as séries até que o resultado não seja mais alterado, portanto, sua precisão é limitada apenas pela precisão do tipo de ponto flutuante.

Como funciona

®Ḥ‘©r0Ç€s2_@/µÐL  Main link, Argument: A (matrix)

             µÐL  Loop; apply the chain until the results are no longer unique.
                  Return the last unique result.
®                   Yield the value of the register (initially zero).
 Ḥ                  Unhalve/double it.
  ‘©                Increment and copy the result (n) to the register.
    r0              Range; yield [n, ..., 0].
      ǀ            Apply the helper link to each k in the range.
        s2          Split the results into chunks of length 2. Since n is always
                    odd, this yields [[Ç(n), Ç(n-1)], ..., [Ç(1), Ç(0)]].
          _@/       Reduce the columns of the result by swapped subtraction,
                    yielding [Ç(1) - Ç(3) + ... Ç(n), Ç(0) - Ç(2) + ... Ç(n - 1)].


³æ*÷!             Helper link. Argument: k (integer)

³                 Yield the first command-line argument (A).
 æ*               Elevate A to the k-th power.
    !             Yield the factorial of k.
   ÷              Divide the left result by the right one.
Dennis
fonte
2

Matlab, 138 121 52 50 bytes

Como a exponenciação de matriz é permitida (o que eu não notei primeiro, d'oh), não preciso mais definir minha função auxiliar, e tudo pode ser resolvido trivialmente:

A=input('')*i;a=expm(A);b=expm(-A);[(b-a)*i,a+b]/2

A entrada deve ser uma matriz, por exemplo, [1,2;4,5]ou alternativamente[[1,2];[3,4]]

Uma coisa inesperada (em retrospectiva não tão inesperada) é que as matrizes cosseno e seno ainda satisfazem

I = sin(A)^2+cos(A)^2
flawr
fonte
Não é A^0o mesmo que eye(size(A))?
FryAmTheEggman
Oh, você está certo, obrigado!
Flawr 05/05
2
Por que não usar expm?
Luis Mendo 5/05
2
De acordo com a identidade: espero que eles satisfaçam essa identidade, considerando que a forma escalar foi usada para estender as funções às matrizes!
Mego 5/05
1
Bem, então tudo se torna quase trivial.
Flawr 5/05
2

Matlab, 37 bytes

@(A){imag(expm(i*A));real(expm(i*A))}
Rainer P.
fonte
2

C ++, 305 bytes

#include<cmath>
#include<iostream>
#include<vector>
int x,i=0, j;void p(std::vector<double> v){int x=sqrt(v.size());for(i=0;i<x;i++){for(j=0;j<x;j++) std::cout << v[x] << " ";std::cout << "\n";}}int main(){std::vector<double> s, c;while(std::cin >> x){s.push_back(sin(x));c.push_back(cos(x));}p(s);p(c);}

Entrada é uma lista de números que são um quadrado perfeito no stdin. A saída é uma matriz 2D bastante impressa no stdout

HSchmale
fonte
0

Julia 0.4, 28 bytes

A->imag({E=expm(im*A),im*E})

Input é uma matriz de flutuadores, output é uma matriz de matrizes. Experimente online!

Dennis
fonte
0

Sábio, 44 ​​bytes

lambda A:map(exp(I*A).apply_map,(imag,real))

Experimente online .

Essa função anônima retorna uma lista de 2 matrizes correspondentes a sin(A)e cos(A), respectivamente. exp(I*A)calcula a exponencial da matriz para I*A( Acom todos os elementos multiplicados pela unidade imaginária) e matrix.apply_map(f)retorna uma matriz onde ffoi aplicada a todos os seus elementos. Aplicando image real(as funções para obter as partes imaginárias e reais de um valor escalar) às matrizes, obtemos os valores de sin(A)e cos(A), graças à famosa identidade de Euler (referenciada no texto do desafio).

Mego
fonte