Trigonometría matricial

13

Introducción

Las dos funciones trigonométricas más comunes, siney cosine(o sinycos para abreviar), pueden extenderse para ser funciones con valores de matriz. Una forma de calcular los análogos con valores de matriz es la siguiente:

Considere estas dos identidades trigonométricas importantes:

identidades trigonométricas

Usando estas identidades, podemos derivar las siguientes ecuaciones para siny cos:

funciones trigonométricas

La matriz exponencial existe para todas las matrices cuadradas y viene dada por:

matriz exponencial

donde A 0 es la matriz de identidad I con las mismas dimensiones que A . Usando la matriz exponencial, estas dos funciones trigonométricas (y, por lo tanto, todas las demás funciones trigonométricas) pueden evaluarse como funciones de matrices.

El reto

Dada una matriz cuadrada A , genera los valores de sin(A)y cos(A).

Reglas

  • La entrada y la salida pueden estar en cualquier formato conveniente y razonable (matriz 2D, formato de matriz de su idioma, etc.).
  • Puede escribir un solo programa, dos programas independientes, una sola función o dos funciones. Si elige escribir dos funciones, el código puede compartirse entre ellas (como las importaciones y las funciones auxiliares).
  • Los valores de la matriz de entrada siempre serán enteros.
  • Su solución puede tener problemas de precisión como resultado de la imprecisión de punto flotante. Si su lenguaje tenía valores mágicos de precisión infinita, entonces su solución debería funcionar perfectamente (ignorando el hecho de que requeriría tiempo y / o memoria infinitos). Sin embargo, dado que esos valores mágicos de precisión infinita no existen, las imprecisiones causadas por la precisión limitada son aceptables. Esta regla está en su lugar para evitar complicaciones resultantes de requerir una cantidad específica de precisión en la salida.
  • No se permiten los componentes integrados que calculan funciones trigonométricas para argumentos de matriz (incluidas las funciones trigonométricas hiperbólicas). Se permiten otras matrices integradas de la matriz (como la multiplicación, exponenciación, diagonalización, descomposición y la exponencial de la matriz).

Casos de prueba

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

Otras lecturas

Esta excelente pregunta en Math.SE incluye algunas derivaciones alternativas de los análogos de funciones trigonométricas con valores de matriz.

Mego
fuente
Tengo sin([[1, 0, 1], [0, 0, 0], [0, 1, 0]]) = {{0.841, -0.158, 0.841}, {0, 0, 0}, {0, 1, 0}}con Mathematica, ¿puedes verificar?
kennytm
1
@kennytm Eso es lo que muestra el caso de prueba.
Mego
1
@Mego Aparentemente, todas las respuestas existentes deberían eliminarse.
Feersum
3
@Mego Es completamente irracional pensar que todos los componentes internos basados ​​en coma flotante usan un algoritmo exacto (o uno que sería exacto si las operaciones de coma flotante fueran reemplazadas por operaciones de "número real").
Feersum
1
@feersum He abordado eso en mi última edición:(ignoring the fact that it would require infinite time and/or memory)
Mego

Respuestas:

6

Julia, 33 19 bytes

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

Esta es una función que acepta una matriz bidimensional de flotadores y devuelve una tupla de tales matrices correspondiente al coseno y seno, respectivamente. Tenga en cuenta que este es el reverso del orden dado en los casos de prueba, en los que el seno se enumera primero.

Para una matriz A de valor real , tenemos

seno

y

coseno

Es decir, el seno y el coseno de A corresponden a las partes imaginarias y reales de la matriz exponencial e iA . Ver Funciones de matrices (Higham, 2008).

Pruébalo en línea!(incluye todos los casos de prueba)

¡Guardado 14 bytes gracias a Dennis!

Alex A.
fuente
6

Mathematica, 27 bytes

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

Basado en @ Rainer P. la solución de

Toma la matriz cuadrada Acomo argumento y genera una lista que contiene{sin(A), cos(A)} .

La entrada está formateada Npara obtener un valor numérico en lugar de una fórmula exacta larga y Columnpara mostrar los resultados de sin(A)y cos(A)como matrices separadas en lugar de una lista anidada.

Ejemplo

Calcular los valores por separado requiere 38 bytes

{(#2-#)I,+##}/2&@@MatrixExp/@{I#,-I#}&
millas
fuente
6

Jalea , 23 22 bytes

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

Pruébalo en línea!

Antecedentes

Este enfoque calcula directamente la serie de Taylor para seno y coseno , es decir,

fórmula

Aumenta el número de términos iniciales de ambas series hasta que el resultado ya no cambia, por lo que su precisión solo está limitada por la precisión del tipo de punto flotante.

Cómo 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
fuente
2

Matlab, 138121 52 50 bytes

Como la exponenciación matricial está permitida, (lo que no noté primero, por supuesto) ya no necesito definir mi función auxiliar, y todo se puede resolver trivialmente:

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

La entrada debe ser una matriz, por ejemplo, [1,2;4,5]o alternativamente[[1,2];[3,4]]

Una cosa inesperada (en retrospectiva no tan inesperada) es que el coseno y la matriz sinusoidal aún satisfacen

I = sin(A)^2+cos(A)^2
falla
fuente
¿No es lo A^0mismo que eye(size(A))?
FryAmTheEggman
Oh, tienes razón, gracias!
flawr
2
¿Por qué no usar expm?
Luis Mendo
2
Según la identidad: ¡espero que satisfagan esa identidad, teniendo en cuenta que la forma escalar se usó para extender las funciones a las matrices!
Mego
1
Bueno, entonces todo se vuelve casi trivial.
flawr
2

Matlab, 37 bytes

@(A){imag(expm(i*A));real(expm(i*A))}
Rainer P.
fuente
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);}

La entrada es una lista de números que son un cuadrado perfecto en stdin. La salida es una matriz 2d bastante impresa en stdout

HSchmale
fuente
0

Julia 0.4, 28 bytes

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

La entrada es una matriz de flotadores, la salida es una matriz de matrices. Pruébalo en línea!

Dennis
fuente
0

Sabio, 44 ​​bytes

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

Pruébalo en línea .

Esta función anónima devuelve una lista de 2 matrices correspondientes a sin(A)y cos(A), respectivamente. exp(I*A)calcula la matriz exponencial para I*A( Acon todos los elementos multiplicados por la unidad imaginaria) y matrix.apply_map(f)devuelve una matriz donde fse ha aplicado a todos sus elementos. Al aplicar imagy real(las funciones para obtener las partes imaginarias y reales de un valor escalar) a las matrices, obtenemos los valores sin(A)y cos(A), gracias a la famosa identidad de Euler (referenciada en el texto del desafío).

Mego
fuente