Codice golf una matrice ortogonale casuale


9

Una matrice ortogonale è una matrice quadrata con voci reali le cui colonne e file sono vettori di unità ortogonali (cioè vettori ortogonali).

Ciò significa che M ^ TM = I, dove I è la matrice dell'identità e ^ T indica la trasposizione della matrice.

Si noti che questo non è ortogonale "ortogonale speciale", quindi il determinante di M può essere 1 o -1.

Lo scopo di questa sfida non è la precisione della macchina, quindi se M ^ TM = I entro 4 decimali andrà bene.

Il compito è scrivere un codice che accetta un numero intero positivo n > 1e genera una matrice ortogonale n per n casuale . La matrice deve essere scelta casualmente e uniformemente da tutte le matrici n da n ortogonali. In questo contesto, "uniforme" è definita in termini della misura di Haar, che richiede essenzialmente che la distribuzione non cambi se moltiplicata per qualsiasi matrice ortogonale liberamente scelta. Ciò significa che i valori della matrice saranno valori in virgola mobile nell'intervallo da -1 a 1.

L'input e l'output possono essere in qualsiasi forma che ritieni conveniente.

Si prega di mostrare un esempio esplicito del codice in esecuzione.

Non è possibile utilizzare alcuna funzione di libreria esistente che crea matrici ortogonali. Questa regola è un po 'sottile, quindi spiegherò di più. Questa regola vieta l'uso di qualsiasi funzione esistente che accetta alcuni (o nessun) input e genera una matrice di dimensioni almeno n per n che è garantita essere ortogonale. A titolo di esempio estremo, se si desidera la matrice identità n per n, è necessario crearla da soli.

È possibile utilizzare qualsiasi libreria di generatore di numeri casuali standard per scegliere numeri casuali di propria scelta.

Il codice dovrebbe essere completato al massimo entro pochi secondi per n < 50.


Quindi è vietato l'uso della matrice di identità integrata?
JungHwan Min,

@JHM Non puoi usarlo per creare almeno una matrice di identità n by n.

Che dire diag? Crea una matrice diagonale che è davvero ortogonale ma non sempre ortogonale.
Karl Napf,

Questo sembra essere un esempio di "do X senza Y", che - così il consenso - dovrebbe essere evitato.
Flawr,

1
Le matrici diagonali non sono matrici ortogonali, quindi diagdovrebbe essere ok.
Angs,

Risposte:


7

Haskell, 169 150 148 141 132 131 byte

import Numeric.LinearAlgebra
z=(unitary.flatten<$>).randn 1
r 1=asRow<$>z 1
r n=do;m<-r$n-1;(<>diagBlock[m,1]).haussholder 2<$>z n

Estendi in modo ricorsivo una matrice ortogonale di dimensioni n-1aggiungendo 1 all'angolo in basso a destra e applica una riflessione casuale della Casa. randndà una matrice con valori casuali da una distribuzione gaussiana e z dfornisce un vettore unitario distribuito uniformemente in ddimensioni.

haussholder tau vrestituisce la matrice I - tau*v*vᵀche non è ortogonale quando vnon è un vettore unitario.

Uso:

*Main> m <- r 5
*Main> disp 5 m
5x5
-0.24045  -0.17761   0.01603  -0.83299  -0.46531
-0.94274   0.12031   0.00566   0.29741  -0.09098
-0.02069   0.30417  -0.93612  -0.13759   0.10865
 0.02155  -0.83065  -0.35109   0.32365  -0.28556
-0.22919  -0.41411   0.01141  -0.30659   0.82575
*Main> (<1e-14) . maxElement . abs $ tr m <> m - ident 5
True

Fare la 1×1matrice richiede troppo spazio per i miei gusti, un caso speciale solo per ottenere zero da una variabile casuale gaussiana: / (Senza di essa, c'è una possibilità infinitesimale di ottenere una colonna zero)
Angs

Mi piace il tuo spirito nel renderlo totalmente corretto, ma penso che tu possa abbandonare quel requisito. Nel mio codice c'è anche la possibilità che 2 righe siano linearmente dipendenti e che a nessuno importa.
Karl Napf,

@KarlNapf, ho escogitato un modo per perdere due byte da quella parte, quindi il problema è stato parzialmente risolto :)
Angs

Ah, va bene, cancellando i miei commenti ...
Karl Napf,

Sempre felice quando vince una risposta Haskell!

4

Python 2 + NumPy, 163 byte

Grazie a xnor per aver sottolineato l'uso di valori casuali distribuiti normali anziché uniformi.

from numpy import*
n=input()
Q=random.randn(n,n)
for i in range(n):
 for j in range(i):u=Q[:,j];Q[:,i]-=u*dot(u,Q[:,i])/dot(u,u)
Q/=(Q**2).sum(axis=0)**0.5
print Q

Utilizza l' ortogonalizzazione di Gram Schmidt su una matrice con valori casuali gaussiani per avere tutte le direzioni.

Il codice dimostrativo è seguito da

print dot(Q.transpose(),Q)

n = 3:

[[-0.2555327   0.89398324  0.36809917]
 [-0.55727299  0.17492767 -0.81169398]
 [ 0.79003155  0.41254608 -0.45349298]]
[[  1.00000000e+00   0.00000000e+00   0.00000000e+00]
 [  0.00000000e+00   1.00000000e+00  -5.55111512e-17]
 [  0.00000000e+00  -5.55111512e-17   1.00000000e+00]]

n = 5:

[[-0.63470728  0.41984536  0.41569193  0.25708079  0.42659843]
 [-0.36418389  0.06244462 -0.82734663 -0.24066123  0.3479231 ]
 [ 0.07863783  0.7048799   0.08914089 -0.64230492 -0.27651168]
 [ 0.67691426  0.33798442 -0.05984083  0.17555011  0.62702062]
 [-0.01095148 -0.45688226  0.36217501 -0.65773717  0.47681205]]
[[  1.00000000e+00   1.73472348e-16   5.37764278e-17   4.68375339e-17
   -2.23779328e-16]
 [  1.73472348e-16   1.00000000e+00   1.38777878e-16   3.33066907e-16
   -6.38378239e-16]
 [  5.37764278e-17   1.38777878e-16   1.00000000e+00   1.38777878e-16
    1.11022302e-16]
 [  4.68375339e-17   3.33066907e-16   1.38777878e-16   1.00000000e+00
    5.55111512e-16]
 [ -2.23779328e-16  -6.38378239e-16   1.11022302e-16   5.55111512e-16
    1.00000000e+00]]

Si completa in un batter d'occhio per n = 50 e pochi secondi per n = 500.


Non penso che sia uniforme. La tua distribuzione iniziale con un cubo, che ha più roba verso le diagonali. I gaussiani casuali funzionerebbero perché generano una distribuzione sferica simmetrica.
xnor

@xnor fixed. Fortunatamente, questo costava esattamente 1 byte.
Karl Napf,

@xnor Ancora più fortunato, questo ha salvato i byte per-0.5
Karl Napf,

Quasi, hai bisogno che la media del normale sia 0, ma non è più lunga di n.
xnor

-1

Mathematica, 69 byte, probabilmente non competitiva

#&@@QRDecomposition@Array[RandomVariate@NormalDistribution[]&,{#,#}]&

QRDecompositionrestituisce una coppia di matrici, la prima delle quali è garantita come ortogonale (e la seconda non è ortogonale, ma triangolare superiore). Si potrebbe sostenere che questo obbedisce tecnicamente alla lettera della restrizione nel post: non genera una matrice ortogonale, ma una coppia di matrici ....

Mathematica, 63 byte, decisamente non competitiva

Orthogonalize@Array[RandomVariate@NormalDistribution[]&,{#,#}]&

Orthogonalizeè inequivocabilmente vietato dal PO. Comunque, Mathematica è piuttosto bella eh?


You may not use any existing library function which creates orthogonal **matrices**.
Karl Napf,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.