Kod będziemy umieszczali w folderach o strukturze pozwalającej na zapis wszystkich projektów w repozytorium kodu ustalonym indywidualnie dla każdego uczestnika.
programowanie-obiektowe
lub Twoje imię i nazwiskoLab1
pliki utworzone podczas pierwszych zajęćLab2
, Lab3
, itd.Lab2
Klasa Matrix jest macierzą dwuwymiarową, ale dane przechowuje w tablicy jednowymiarowej data
. Informacja o liczbie wierszy i kolumn jest zawarta w polach rows
i cols
public class Matrix { double[]data; int rows; int cols; //... Matrix(int rows, int cols){ this.rows = rows; this.cols = cols; data = new double[rows*cols]; } //... }
Celem ćwiczenia jest implementacja różnych metod klasy Matrix oraz ich przetestowanie. Możesz wpierw wykonać punkt 2.11 i dodawać kod testujący na bieżąco…
Matrix(double[][] d){
tworzący macierz na podstawie tablicy - liczba kolumn ma być ustalona na podstawie najdłuższego wiersza w d, brakujace elementy zerowe.
Matrix m = new Matrix(new double[][]{{1,2,3,4},{5,6},{7,8},{9}});
double[][] asArray()
double get(int r,int c) void set (int r,int c, double value)
Publiczna funkcja toString
powinna zwracać tekstową reprezentację obiektu. Klasa String
jest niemodyfikowalna (immutable), dlatego do przygotowania tekstu użyj klasy StringBuilder
. Obiekty tej klasy są modyfikowalne i bufor dla tekstu może automatycznie przyrastać w miarę dodawania kolejnych fragmentów. Przeciążona metoda append()
pozwala na dopisywania tekstowej reprezentacji obiektów różnych typów (String
, Object
, double
, float
, int
, itd.)
public String toString(){ StringBuilder buf = new StringBuilder(); buf.append("[") for(int i=0;i<rows;i++){ buf.append("["); //... } //... return buf.toString(); }
void reshape(int newRows,int newCols){ if(rows*cols != newRows*newCols) throw new RuntimeException(String.format("%d x %d matrix can't be reshaped to %d x %d",rows,cols,newRows,newCols)); }
Na razie informuj o błędach za pomocą wyjątku RuntimeException. Jest to bardzo niewłaściwe i żaden programista Javy nigdy nie powinien tego robić. Ale niektórzy tak robią i zostaje w bibliotekach na długie lata.
Metoda powinna zwracać tablicę określającą liczbę wierszy i kolumn
int[] shape()
Matrix add(Matrix m)
Zwraca ona macierz, której elementy spełniają
assert( get(i,j) == this.get(i,j)+m.get(i,j) )
Matrix sub(Matrix m){...} Matrix mul(Matrix m){...} Matrix div(Matrix m){...}
oraz dodawanie, mnożenie, dzielenie, odejmowanie skalarów
Matrix add(double w){...} // dodaje wartość w do każdego elementu Matrix sub(double w){...} // odejmuje wartośc w od kazdego elementu Matrix mul(double w){...} // mnoży każdy element przez skalar w Matrix div(double w){...} // dzieli każdy element przez skalar w
W wyniku pomnożenia A(r x n) * B(n x m) ma powstać macierz C(r x m)
Matrix dot(Matrix m)
Norma Frobeniusa to po prostu suma kwadratów elementów. https://en.wikipedia.org/wiki/Matrix_norm#Frobenius_norm
double frobenius()
Czyli jeżeli odejmiemy macierz od siebie - to powinna powtać macierz o zerowej normie Frobeniusa. Jeśli podzielimy przez siebie - norma powinna wynosić rows * cols
Uwaga To zadanie przeniesione na następne laboratorium
Dla każdej z wcześniej podanych metod napisz kod testowy.
TestMatrix
(w tym samym pakiecie)testXXX
, np:testMatrix()
- test konstruktoratestAdd()
- test dodawaniamain
Często spotykaną konwencją jest stosowanie metod statycznych, które tworzą skonfigurowany obiekt Zaimplementuj typowe metody:
public static Matrix random(int rows, int cols){ Matrix m = new Matrix(rows,cols); Random r = new Random(); m.set(0,0,r.nextDouble()); //... wypełnij wartościami losowymi return m; }
Wywołanie:
Matrix r = Matrix.random(2,3);
Macierz jednostkowa
public static Matrix eye(int n){ Matrix m = new Matrix(n,n); //... wypełnij jedynkami na przekątnej return m; }
Jeżeli ktoś ma ochotę może napisać metodę inv()
zwracającą odwrotność macierzy. Macierz może być odwrócona metodą eliminacji Gaussa.
Znalazłem gdzieś na dysku stary kod w C++ z 1995 roku. Może się przydać jako źródło inspiracji… Wydaje mi się, że działał?
void Matrix::swapRows(int i1,int i2) { for(int j=0;j<n;j++){ double tmp=x[i1][j]; x[i1][j]=x[i2][j]; x[i2][j]=tmp; } } void Matrix::invert() { int i,j,k; Matrix out(n); for(i=0; i<n; i++){ // Find pivot row double max=fabs(x[i][i]); int pivot=i; for(k=i;k<n;k++){ if(max<fabs(x[k][i])){ max=fabs(x[k][i]); pivot=k; } } if(i!=pivot)swapRows(i,pivot); if(i!=pivot)out.swapRows(i,pivot); if(x[i][i] != 1.0){ double divby=x[i][i]; if( fabs(divby)>verySmall ){ for(j=0;j<n;j++){ out.x[i][j]/=divby; x[i][j]/=divby; } }else { throw -1; } } for(j=0;j<n;j++){ if(j!=i){ if(x[j][i]!=0){ double mulby=x[j][i]; for(k=0;k<n;k++){ x[j][k]-=mulby*x[i][k]; out.x[j][k]-=mulby*out.x[i][k]; } } } } } *this=out; }