Lab03

Laboratorium 3 - Przykładowe - Klasy/Struktury, Dziedzicznie, Właściwości, Modyfikatory dostępu #

Wprowadzenie #

Zadaniem na dzisiejszych laboratoriach jest stworzenie prostej biblioteki odpowiedzialnej za działania na macierzach.

Uwaga #

W celu przechodzenia do następnych etapów należy odkomentowywać poszczególne linijki typu #define STAGE0X znajdujące się na początku pliku Program.cs. Inna ingerencja w ten plik jest zakazana.

Kod początkowy #

Matrices

Etap 1 (4 pkt) #

W folderze Matrix stwórz abstrakcyjną klasę Matrix, która będzie posiadała:

  • konstruktor przyjmujący ilość wierszy i kolumn macierzy jako int
  • publiczną właściwość Rows, zwracająca ilość wierszy w macierzy
  • publiczną właściwość Columns, zwracająca ilość kolumn w macierzy
  • abstrakcyjny indeksator, który przyjmuje numer wiersza i kolumny. Pozwala na odczyt i zapis wartości float w konkretną komórkę macierzy.
  • przeciążoną metodę ToString, w taki sposób, aby macierze były drukowane tak samo jak w przykładowym wyjściu programu

Stwórz następujące klasy dziedziczące po Matrix: DenseMatrix i SparseMatrix.

DenseMatrix powinna przechowywać elementy w formie tablicy prostokątnej.

SparseMatrix powinna przechowywać w słowniku jedynie niezerowe elementy macierzy. Taka implementacja zmniejsza ilość potrzebnej pamięci w przypadku przechowywania macierzy rzadkich, czyli takich w których znaczna ilość wartości jest równa zero.

Obie klasy powinny posiadać konstruktor przyjmujący liczbę wierszy i kolumn. Nowo zainicjalizowane macierze powinny być wypełnione zerami.

Program powinien sprawdzać poprawność argumentów. W razie niepoprawności powinien generować wyjątek typu ArgumentException z odpowiednim komentarzem.

Wskazówki #

Punktacja #

Po 2 punkty za każdą klasę pochodną.

Etap 2 (3 pkt) #

Do klasy Matrix dodaj abstrakcyjne metody Identity, Transpose i Norm. Zaimplementuje w klasach pochodnych.

Metoda Identity niczego nie przyjmuje, ani niczego nie zwraca. Wypełnia jedynie macierz tak, aby była identycznościowa. W przypadku macierzy niekwadratowej metoda powinna generować wyjątek typu InvalidOperationException.

Metoda Transpose zwraca macierz po transpozycji.

Metoda Norm zwraca normę macierzy definiowaną jako \[ ||A|| = \sqrt{\sum_i \sum_j A_{i,j}^2}. \]

Implementacje w klasie SparseMatrix powinny mieć liniową zależność czasową względem ilości niezerowych elementów macierzy.

Punktacja #

Po 1 pkt za każdą z metod.

Etap 3 (3 pkt) #

Do klasy Matrix dodaj abstrakcyjną metodę GetInstance, która przyjmuje liczbę wierszy i kolumn i zwraca obiekt typu Matrix. Metoda ta nie powinna być możliwa do wywołania spoza tej klasy i klas pochodnych. Zaimplementuj tę metodę w klasach pochodnych w taki sposób, że każda klasa zwraca instancję swojej klasy z żądaną wielkością.

W klasie Matrix zaimplementuje następujące przeciążenia operatorów:

  • operator dodawania macierzy
  • operator odejmowania macierzy
  • operator mnożenia macierzy
  • operator mnożenia macierzy przez skalar

W implementacji wykorzystaj metodę GetInstance. Dla funkcji przyjmujących jedną macierz powinna zwracać macierz tego samego typu. Dla funkcji przyjmujących dwie macierze zwracana implementacja powinna być taka sama jak lewego (pierwszego) argumentu.

Wskazówki #

Punktacja #

1 za metodę GetInstance, po 0.5 pkt za każde przeciążenie.

Etap 4 (2 pkt) #

W ostatnim etapie wykorzystamy interfejs, który zbudowaliśmy podczas poprzednich etapów. Należy stworzyć klasę MatrixAlgorithms, a w niej statyczną metodę PseudoInverse przyjmującą Matrix oraz maksymalną liczbę iteracji, która ma domyślą wartość 1000. Za wartość \( \epsilon \) przyjmij \( 10^{-7} \) .

Na potrzeby laboratorium będziemy się zajmować tylko kwadratowymi macierzami.

Algorytm:

\( A \) - input square matrix

\( I \) - identity matrix

\( \alpha = \frac{1}{||A||^2} \)
\( A1 = \alpha \cdot A^T \)
\( \text{for } i=1...maxIter: \)
\( \qquad A2 = A1 + A1 \cdot (I - A\cdot A1) \)
\( \qquad \text{if } ||A2-A1|| < \epsilon: \)
\( \qquad \qquad \text{break} \)
\( \qquad A1 = A2 \)
\( \text{return A2} \)

Punktacja #

Poprawna implementacja algorytmu - 2 pkt. Częściowa implementacja - 1 pkt

Przykładowe rozwiązanie #

Matrices