Μετατροπή μήτρας από μορφή πίνακα σε μορφή καταλόγου μη-μηδενικών στοιχείων και αντιστρόφως Παράδειγμα 1: >> A=[1 0 0 2 1 0 3 0 0 1 0 0 2 2 0 4 0 0 6 0 0 0 1 0 5] A = 1 0 0 2 1 0 3 0 0 1 0 0 2 2 0 4 0 0 6 0 0 0 1 0 5 >> A = sparse(a) A = (1,1) 1 (4,1) 4 (2,2) 3 (3,3) 2 (5,3) 1 (1,4) 2 (3,4) 2 (4,4) 6 (1,5) 1 (2,5) 1 (5,5) 5 >> spy(a)
Παράδειγμα 2: Κατασκευή τριδιαγώνιας μήτρας: >> T=diag(ones(20,1),-1) -2*diag(ones(21,1)) + diag(ones(20,1),1); >> T=sparse(T) T = (1,1) -2 (2,1) 1 (1,2) 1 (2,2) -2 (3,2) 1 (2,3) 1 (3,3) -2 (4,3) 1 (3,4) 1 (4,4) -2 (5,4) 1 (4,5) 1 (5,5) -2
(6,5) 1 (5,6) 1 (6,6) -2 (7,6) 1 (6,7) 1 (7,7) -2 (8,7) 1 (7,8) 1 (8,8) -2 (9,8) 1 (8,9) 1 (9,9) -2 (10,9) 1 (9,10) 1 (10,10) -2 (11,10) 1 (10,11) 1 (11,11) -2 (12,11) 1 (11,12) 1 (12,12) -2 (13,12) 1 (12,13) 1 (13,13) -2 (14,13) 1 (13,14) 1 (14,14) -2 (15,14) 1 (14,15) 1 (15,15) -2 (16,15) 1 (15,16) 1 (16,16) -2 (17,16) 1 (16,17) 1 (17,17) -2 (18,17) 1 (17,18) 1 (18,18) -2 (19,18) 1 (18,19) 1 (19,19) -2 (20,19) 1 (19,20) 1 (20,20) -2 (21,20) 1 (20,21) 1 (21,21) -2
>> spy(t) Παράδειγμα 3: Κατασκευή τριδιαγώνιας μήτρας απευθείας σε μορφή καταλόγου: >> n=21; W = diag(sparse(ones(n-1,1)),-1)... - 2*diag(sparse(ones(n,1))) + diag(sparse(ones(n-1,1)),1) W = (1,1) -2 (2,1) 1 (1,2) 1 (2,2) -2 (3,2) 1 (2,3) 1 (3,3) -2 (4,3) 1 (3,4) 1 (4,4) -2 (5,4) 1 (4,5) 1 (5,5) -2 (6,5) 1
(5,6) 1 (6,6) -2 (7,6) 1 (6,7) 1 (7,7) -2 (8,7) 1 (7,8) 1 (8,8) -2 (9,8) 1 (8,9) 1 (9,9) -2 (10,9) 1 (9,10) 1 (10,10) -2 (11,10) 1 (10,11) 1 (11,11) -2 (12,11) 1 (11,12) 1 (12,12) -2 (13,12) 1 (12,13) 1 (13,13) -2 (14,13) 1 (13,14) 1 (14,14) -2 (15,14) 1 (14,15) 1 (15,15) -2 (16,15) 1 (15,16) 1 (16,16) -2 (17,16) 1 (16,17) 1 (17,17) -2 (18,17) 1 (17,18) 1 (18,18) -2 (19,18) 1 (18,19) 1 (19,19) -2 (20,19) 1 (19,20) 1 (20,20) -2 (21,20) 1 (20,21) 1 (21,21) -2 >> spy(w)
>> full(w) ans = -2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-2 Παράδειγμα 4: >> G=100*rand(200,200); >> [row,column,value]=find(g<5); >> spy(g) >> GG=sparse(row,column,value,200,200); >> spy(gg)
Τι συμβαίνει με την αντίστροφη μιας σποραδικής μήτρας; Παράδειγμα 1: >> A1=inv(A) A1 = (1,1) -2.1429 (2,1) -0.0952 (3,1) -1.4286 (4,1) 1.4286 (5,1) 0.2857 (2,2) 0.3333 (1,3) -0.2143 (2,3) 0.0238 (3,3) 0.3571 (4,3) 0.1429 (5,3) -0.0714 (1,4) 0.7857
(2,4) 0.0238 (3,4) 0.3571 (4,4) -0.3571 (5,4) -0.0714 (1,5) 0.4286 (2,5) -0.0476 (3,5) 0.2857 (4,5) -0.2857 (5,5) 0.1429 >> spy(a1) Παράδειγμα 2: Αντιστροφή της τριδιαγωνίου μήτρας: >> T1=inv(T); >> spy(t1)
Παραγοντοποίηση σποραδικής μήτρας Παράδειγμα 1: >> [L,U]=lu(A) L = (1,1) 0.2500 (4,1) 1.0000 (2,2) 1.0000 (3,3) 1.0000 (5,3) 0.5000 (1,4) -0.5000 (5,4) 1.0000 (1,5) 1.0000 U =
(1,1) 4.0000 (2,2) 3.0000 (3,3) 2.0000 (1,4) 6.0000 (3,4) 2.0000 (4,4) -1.0000 (2,5) 1.0000 (4,5) 5.0000 (5,5) 3.5000 >> full(l) ans = 0.2500 0 0-0.5000 1.0000 0 1.0000 0 0 0 0 0 1.0000 0 0 1.0000 0 0 0 0 0 0 0.5000 1.0000 0 >> full(u) ans = 4.0000 0 0 6.0000 0 0 3.0000 0 0 1.0000 0 0 2.0000 2.0000 0 0 0 0-1.0000 5.0000 0 0 0 0 3.5000 >> spy(l)
>> spy(u)
Παράδειγμα 2: >> [L,U]=lu(T); >> spy(l)
>> spy(u)
Μήτρα ταυτότητας σε μορφή καταλόγου Παράδειγμα 1: >> I=speye(5) I = (1,1) 1 (2,2) 1 (3,3) 1 (4,4) 1 (5,5) 1 >> spy(i)
>> I*A ans = (1,1) 1 (4,1) 4 (2,2) 3 (3,3) 2 (5,3) 1 (1,4) 2 (3,4) 2 (4,4) 6 (1,5) 1 (2,5) 1 (5,5) 5 >> A*I ans = (1,1) 1 (4,1) 4 (2,2) 3
(3,3) 2 (5,3) 1 (1,4) 2 (3,4) 2 (4,4) 6 (1,5) 1 (2,5) 1 (5,5) 5 Παράδειγμα 2: >> [m,n]=size(t) m = 21 n = 21 >> spy(i)
Κατασκευή τυχαιοποιημένων μητρών Παράδειγμα 1: Ομοιόμορφη κατανομή >> A=sprand(100,100,0.003); >> spy(a) Παράδειγμα 2: Κανονική κατανομή >> B=sprandn(100,100,0.003); >> spy(b)
Παράδειγμα 3: Συμμετρική τυχαιοποιημένη >> S=sprandsym(100,0.003); >> spy(s)
Παράδειγμα 4: Πολυδιαγώνια μήτρα >> W=rand(100,100); >> T=spdiags(W); >> spy(t)
Αναγνώριση σποραδικότητας Παράδειγμα 1: >> issparse(t) ans = 0 >> issparse(a) ans = 1 Παράδειγμα 2: >> nnz(t) ans =
10000 >> nnz(a) ans = 30 >> nnz(t)/prod(size(t)) ans = 0.5025 >> nnz(a)/prod(size(a)) ans = 0.0030 Εγχειρίδιο MATLAB στο διαδίκτυο http://www.mathworks.com/access/helpdesk/help/techdoc/learn_matlab/bqr_2pl.html Παραδείγματα προγραμματισμού διαδικασιών Παράδειγμα 1: Επίλυση τριωνύμου Επίλυση της εξίσωσης ax^2+bx+c=0 για πραγματικές ρίζες. Προσπάθεια καταπολέμησης του φαινομένου της υποεκχείλισης και αποφυγής του σφάλματος αλληλοεξάλειψης. Η μία ρίζα, η x_1, υπολογίζεται από τον κλασσικό τύπο ενώ η άλλη, που θα απαιτούσε αφαίρεση, υπολογίζεται από το x_1*x_2=c/a. function [x1,x2] = quad_eq(a,b,c) x1 = NaN; x2 = NaN; if ( a == 0.0 ) return; end; f = max( [ abs(a), abs(b), abs(c) ] ); a0 = a/f; b0 = b/f; c0 = c/f; if ( a0 == 0.0 ) return; ΜΑΤLAB Fortran 95 SUBROUTINE quad_eq(a,b,c,x1,x2,error) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c REAL, INTENT(OUT) :: x1, x2 LOGICAL, INTENT(OUT) :: error REAL :: a0, b0, c0, f, d x1 = 0.0; x2 = 0.0 error = a==0.0; IF (error) RETURN f = MAX( ABS(a), ABS(b), ABS(c) )
end; d = b0 * b0-4.0 * a0 * c0; if ( d < 0.0 ) return; end; d = sqrt( d ); if ( b0 > 0.0 ) x1 = ( -b0 - d ) / ( a0 + a0 ); else x1 = ( -b0 + d ) / ( a0 + a0 ); end; x2 = ( c0/a0)/x1; end ΜΑΤLAB Fortran 95 a0 = a/f; b0 = b/f; c0 = c/f error = a0==0.0; IF (error) RETURN d = b0 * b0-4.0 * a0 * c0 error = d<0.0; IF (error) RETURN d = SQRT( d ) IF ( b0 > 0.0 ) THEN x1 = ( -b0 - d ) / ( a0 + a0 ) ELSE x1 = ( -b0 + d ) / ( a0 + a0 ) ENDIF x2 = ( c0/a0)/x1 END SUBROUTINE quad_eq Παράδειγμα 2: Doolittle-Crout αλγόριθμος Ο αλγόριθμος επιλύει συστήματα γραμμικών εξισώσεων Ax=b μέσω παραγοντοποίησης της Α σε κάτω τριγωνική L και άνω τριγωνική U: A=LU. Έχομε τότε LUx=b ή Ly=b και Ux=y. Επιλύουμε πρώτα το Ly=b για y (πρόσω αντικατάσταση) και στην συνέχεια το Ux=y για x (προς τα πίσω αντικατάσταση). Οι αλγόριθμοι του Doolittle και Crout διαφέρουν μόνον ως προς το ποιο από τους παράγοντες L και U κερδίζει την διαγώνιο με στοιχεία μόνον μονάδες και είναι ουσιαστικά αριθμητικά ισοδύναμοι. Οι δύο αυτές διαφορετικές εκδοχές δίδονται σε διαφορετικές γλώσσες πιο κάτω. Προσέξτε την ομοιότητα! (Παρατήρηση: Στον κώδικα του Matlab επηρεάζουμε το b κατά την διάρκεια της παραγοντοποίησης και γι' αυτό δεν χρειάζεται η πρόσω αντικατάσταση. Βέβαια θα μπορούσαμε να είχαμε κάνει το ίδιο ακριβώς και στον δεύτερο κώδικα). Παρόμοιοι αλγόριθμοι θα χρησιμοποιηθούν για σποραδικά συστήματα. function [A,b]=Doolittle_Crout(A,b) MATLAB FORTRAN 95 SUBROUTINE ludecomp(n,a,b,ifail) % On return, A's diagonal and upper triangular part constitutes the U factor, % while the lower triangular part together with a diagonal of 1s % constitutes the L factor. % b contains the solution to Ax=b % initial data check [n,m]=size(a); if n~=m error('a not square') else! Computation of an LU decomposition of the matrix A, i.e. A = L U where the uniqueness of the decomposition is obtained by diag(u) = 1 Upon return, the lower triangular part of A, including its diagonal, constitutes the factor L, while the upper triangular part of A, excluding its diagonal and replacing it by 1s,constitute the factor U. IMPLICIT NONE INTEGER, INTENT(IN) :: n INTEGER, INTENT(OUT):: ifail REAL, DIMENSION(n,n):: a REAL, DIMENSION(n) :: b
m=size(b); if n~=m error('b wrong size') else MATLAB FORTRAN 95 % run main algorithm and check for zero pivots for k=1:n for i=k:n A(k,i)=A(k,i)-A(k,1:k-1)*A(1:k-1,i); end b(k)=b(k)-a(k,1:k-1)*b(1:k-1); if A(k,k)==0 error('zero pivot') return else for i=k+1:n A(i,k) = ( A(i,k) - A(i,1:k-1)*A(1:k-1,k) )/A(k,k); end end end %forward substitution not needed since it has already be done above during the factorization process (look at line altering b(k) ) INTEGER :: i, j,k ifail = 0 DO j = 1, n DO i = j, n a(i,j) = a(i,j) - DOT_PRODUCT( a(i,1:j-1), a(1:j-1,j) ) ENDDO IF ( a(j,j) == 0.0 ) THEN ifail = -j; RETURN ENDIF DO i = j+1, n a(j,i) = ( a(j,i) - DOT_PRODUCT( a(j,1:j-1), a(1:j-1,i) ) ) / a(j,j) ENDDO END DO! Forward substitution DO k = 1, n IF ( a(k,k) == 0.0 ) THEN ifail = -k; RETURN ENDIF b(k) = ( b(k) - DOT_PRODUCT( a(k,1:k-1), b(1:k-1) ) ) / a(k,k) ENDDO % backward substitution to obtain the solution for k=n:-1:1 b(k) = ( b(k) - A(k,k+1:n)*b(k+1:n) )/A(k,k) end end end return end! Backward substitution DO k = n, 1, -1 b(k) = b(k) - DOT_PRODUCT( a(k,k+1:n), b(k+1:n) ) ENDDO END SUBROUTINE ludecomp