2015-09-16 13 views
5

In Matlab, spesso devo lavorare con matrici provenienti dal codice di un'altra persona, e non c'è sempre una chiara convenzione sull'orientamento delle matrici (trasposte o meno) e se una certa riga/colonna viene aggiunta. Perciò io trascorro molto del mio tempo di debug il seguente erroreAggiungere il codice di debug ai messaggi di errore in Matlab?

Error using * 
Inner matrix dimensions must agree. 

E errori simili per +, .*, -, ecc.

Risparmierebbe un sacco di tempo se potessi modificare questo messaggio di errore per includere le dimensioni, in modo che conosca quale da modificare e potenzialmente indovinare dove è entrata la dimensione errata. Quindi, vorrei modificare in qualche modo il messaggio di errore per includere le dimensioni a portata di mano:

Error using * 
Inner matrix dimensions must agree: 243 x 23 and 98 x 23. 

questo è possibile, e se sì, come posso farlo? Attualmente passo molto tempo ad aggiungere/rimuovere/testare il codice di debug che stampa queste informazioni, quindi qualsiasi soluzione che avvicini questo più vicino sarebbe utile!

+0

modificando il messaggio di errore effettivo è possibile (credo), trovando il file .m della funzione di moltiplicazione della matrice e quindi cercare l'output dell'errore all'interno di quel codice e includere 'size()' per entrambe le matrici. – Adriaan

+4

Usa 'dbstop if error' e Matlab interromperà l'esecuzione esattamente dove si verifica l'errore. Puoi vedere le dimensioni variabili nel browser delle variabili e provare direttamente il tuo codice migliorato. – Daniel

+0

Grazie, non sapevo di 'dbstop if error', comando molto utile! – user1111929

risposta

5

Ogni operatore aritmetico in Matlab ha un associated method che viene chiamato quando si richiama quell'operatore. Ad esempio, il metodo corrispondente a * (moltiplicazione di matrice) è chiamato mtimes.

Per ciascun operatore, è possibile definire un metodo per le variabili di tipo double che ombre il metodo integrato e modifica il suo comportamento: nel tuo caso, includere il controllo degli errori personalizzato e quindi chiamare il metodo incorporato.

I vantaggi di questo approccio sono:

  • Nessuna modifica nel codice è neccessary: userete *, *., + ecc normalmente; ma il loro comportamento (di controllo degli errori) cambierà.

  • Quando (si pensa) il debug è completato, è sufficiente rimuovere i metodi personalizzati dal percorso. Questo sarà ripristinare il normale comportamento e quindi evitare qualsiasi penalità di velocità. Successivamente, se è necessario eseguire di nuovo il debug, è sufficiente posizionare nuovamente i metodi modificati sul percorso.

Nel seguente testo uso * e la sua associata mtimes come esempio.Il tuo nuovo metodo mtimes deve essere inserito nel percorso di Matlab, in una cartella appropriata in modo che abbia la precedenza sulla bulina mtimes. Ciò significa che la cartella dovrebbe essere in Matlab path. Oppure puoi usare la cartella corrente, che ha la precedenza su tutte le altre.

All'interno della cartella selezionata creare una cartella denominata @double e creare un file denominato mtimes.m. Questo dice a Matlab che il tuo file mtimes.m deve essere usato ogni volta che lo * viene invocato con gli ingressi double.

Il contenuto di mtimes.m whould essere qualcosa secondo le seguenti linee:

function C = mtimes(A,B) 
if ndims(A)~=2 || ndims(B)~=2 
    %// number of dimensions is incorrect 
    error('MATLAB:mtimes_modified:ndims', ... 
     'One of the arrays is not a matrix: numbers of dimensions are %i and %i',... 
     ndims(A), ndims(B)); 
elseif max(size(A))>1 & max(size(B))>1 size(A,2)~=size(B,1) 
    %// dimensions are not appropriate for matrix multiplication, 
    %// or for multiplying by a matrix by a scalar 
    error('MATLAB:plus_modified:dimagree',... 
     'Sizes do not match: %i x %i and %i x %i', ... 
     size(A,1), size(A,2), size(B,1), size(B,2)); 
else 
    C = builtin('mtimes', A, B); %// call actual mtimes to multiply matrices 
end 

ampia:

>> rand(3,4,5)*rand(6,7) 
Error using * (line 3) 
One of the arrays is not a matrix: numbers of dimensions are 3 and 2 

>> rand(3,4)*rand(2,5) 
Error using * (line 7) 
Sizes do not match: 3 x 4 and 2 x 5 

>> rand(3,4)*rand(4,2) 
ans = 
    0.3162 0.3009 
    1.2628 0.7552 
    1.2488 0.8559 
+0

ne ho letto da qualche parte molto tempo fa, ma per me la tua risposta è il primo esempio concreto. altamente raccomandato!!! – scmg

+0

@scmg Grazie! –

7

È possibile utilizzare un try-catch block:

a = rand(12); 
b = rand(10); 

try 
    c = a*b; 
catch err 
    % Because err is read-only, generate new error structure 
    % We can copy most of old one 

    newerr.identifier = err.identifier; 
    newerr.cause = err.cause; 
    newerr.stack = err.stack; 
    newerr.message = sprintf('%s size(a): [%u, %u] size(b): [%u, %u]', err.message, size(a), size(b)); 
    error(newerr) % Throw new error 
end 

Ora otteniamo:

Error using testcode (line 5) 
Inner matrix dimensions must agree. size(a): [12, 12] size(b): [10, 10] 
+0

Ma allora devi fare tutto questo ogni volta che devi moltiplicare le matrici? Non sarebbe meglio metterlo in una funzione? –

+0

@LuisMendo È solo un esempio, l'utente può implementarlo come vorrebbero. – excaza

2

Se si deve fare con molti calcoli di matrici, quindi è possibile scrivere funzioni in questo modo, per esempio:

function C = matproduct(A, B) 
try 
    C = A * B; 
catch ME 
    switch ME.identifier 
     case 'MATLAB:dimagree' 
      msg = [ME.message, ' Size of ', inputname(1), ' :', num2str(size(A)), '. Size of ', inputname(2), ' :', num2str(size(B)), '.']; 
     case 'MATLAB:innerdim' 
      msg = [ME.message, ' Size of ', inputname(1), ' :', num2str(size(A)), '. Size of ', inputname(2), ' :', num2str(size(B)), '.']; 
     % other cases and corresponding modified msg here 
    end 
    throw(MException(ME.identifier, msg)); 
end 
end 

Tuttavia non sono sicuro che influenzi la velocità ... E se lo usi come per a * b * c ad esempio, quindi il nome del primo ingresso non può essere visualizzato.