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.