MW 2008-07-07
[UTF-8]


Wymagania dla programu przygotowywanego w ramach praktyki
=========================================================

Wstęp
-----
Celem jest przygotowanie narzędzi do filtrowania i obróbki danych liczbowych przechowywanych  w postaci kolumn i wierszy z liczbami w zwykłych plikach tekstowych.
Ma on zastąpić skrypty pisanie osobno do każdego rodzaju operacji i wykorzystujące polecenia takie jak join, col, cut, paste, grep, awk, sed itp.
Na początek warto przeszukać internet - może są jakieś narzędzia, które byłyby pomocne, np. jak źródło pomysłów? Albo wręcz kod do wykorzystania?

Wymagania ogólne
----------------
- narzędzie ma być w stylu tradycyjnych rozwiązań uniksowych: obsługiwane za pomocą opcji linii poleceń, działające także jako filtr (tzn. domyślnie dane są czytane z stdin, ale oprócz tego opcja np. -i|--input-files ... , zwłaszcza, że często na wejście będziemy chcieli przekazać dane z wielu plików);
proszę się wzorować na sposobie działania typowych narzędzi tego typu, np. programów cut, paste, join
- wyniki na stdout lub do pliku zdefiniowanego przez opcję np. -o|--output-file ...
- możliwość rozbudowy o kolejne operacje na danych (poza tymi, które są wymienione w szczegółowych wymaganiach poniżej)
- w miarę możliwości wydajna obsługa nawet dużych ilości danych
- brak ograniczeń na ilość danych (innych niż dostępność zasobów); do zastanowienia: czy miałaby sens i byłaby trudna do implementacji możliwość wyłączenia wczytywania do pamięci wszystkich danych jednocześnie?
- język: prawdopodobnie C++ z wykorzystaniem udogodnień takich jak klasa valarray, pojemniki itp., ale możemy też przedyskutować C lub inne propozycje; warunek: program musi się dać skompilować na Linuksie i windowsie bez użycia jakichkolwiek bibliotek spoza standardu języka i innych ogólnodostępnych na otwartych licencjach typu GPL (może np. Boost? - jest tam sporo przydatnych rzeczy, np. do obsługi opcji linii poleceń)
- wymagana jest dokumentacja kodu (doxygen) oraz podręcznik użytkownika z opisem dostępnych opcji wyświetlany po uruchomieniu z paramaterem --help|-h, oprócz tego również man-page
- o ile to możliwe: wszelkie komunikaty, dokumentacja i komentarze w programie po angielsku (proszę się nie przejmować tym jak dobry ten angielski będzie)
- po przetestowaniu narzędzia proponuję jego udostępnienie na zasadach GPL - jeśli nie ma co do tego zastrzeżeń, to proszę od razu umieszczać na początku każdego pliku źródłowego informację o autorze/autorach i licencji GPL
- GUI do gotowego narzędzia - ewentualnie dopiero jako ostatni etap (najmniej istotny, do przedyskutowania dopiero gdy podstawowa część będzie gotowa)

Wymagania szczegółowe
---------------------
I. format danych wejściowych:
 - tekstowy z liniami zawierającymi jedną lub więcej liczb oddzielonych białymi znakami (spacje, tabulacje);
 - linie z pierwszym niebiałym znakiem # mają być uważane za komentarz
 - linie puste mają być ignorowane
 - linie niepoprawne (np. wartości niedające się zinterpretować jako liczby, brak spodziewanej ilości danych itp.) mają być sygnalizowane na stderr, ale nie powodować przerwania obróbki danych
 - wczytywane liczby należy domyślnie przechowywać jako typ double, z możliwością opcjonalnego wymuszenia traktowania danych z N-tej kolumny jako całkowite
 - zapewnić opcję włączającą porównywanie liczb zmiennoprzecinkowych z zadaną przez użytkownika dokładnością; zastanowić się nad rozwiązaniem domyślnym (zero? 1e-15? -- w każdym razie najlepiej jako #define albo const double, będzie łatwo zmienić)

II. format danych wyjściowych:
 - dane tekstowe, ew. komentarze oznaczone # na początku linii
 - domyślnie tworzona na początku linia komentarza z datą i godziną uruchomienia programu oraz zacytowanym poleceniem uruchamiającym go (w całości, razem ze wszystkimi opcjami); dostępna ma być opcja wyłączająca tworzenie tego komentarza
 - dostępna opcja przekopiowania do wyników pierwszej linii komentarza z każdego pliku wejściowego (z podaniem kolejnego numeru pliku, z którego dany komentarz pochodzi)
 - dostępna opcja przekopiowania do wyników wszystkich komentarzy z wejścia (w takiej kolejności i miejscach, w jakich się pojawiły na wejściu)
 - dostępna opcja wstawienia dowolnego, własnego komentarza przed danymi wynikowymi
 - dostępna opcja zastąpienia brakujących danych, które chcemy wypisać (a np. nie ma takiej kolumny) dowolnym napisem (domyślnie powiedzmy "--")
 - rozdzielać dane wyjściowe (kolejne liczby w linii) spacjami lub - jako opcja - tabulacjami

III. obsługiwane operacje (patrz też przykłady poniżej) - będą dotyczyć wszystkich danych wejściowych jakie są dostępne:

 1) wypisanie wszystkich lub niektórych kolumn z linii, które spełniają jedno lub kilka z kryteriów takich jak:
  - wartość w i-tej kolumnie wynosi ...
  - wartość w i-tej kolumnie jest mniejsza od ... i/lub większa od ...
 2) wypisanie wybranych kolumn ze wszystkich plików wejściowych, zebranych wg:
  - wartości w wybranej kolumnie
  - wg kolejności w jakiej są w plikach wejściowych
  - wg wartości parametru zapisanej we wcześniejszym komentarzu w formacie "NAZWA_PARAMETRU= WARTOŚĆ", np.
 3) podobnie jak 2), ale zamiast wypisywać wybrane kolumny to policzyć z wartości w nich występujących sumę i/lub średnią i/lub odch. standardowe i/lub medianę i/lub podać liczbę danych użytych do obliczeń
 4) zamienić miejscami kolumny i-tą i j-tą (i zapisać do tego samego pliku!)

Przykłady zastosowań:
Mamy dwa pliki wejściowe: a.dat (6 linii) i b.dat (4 linie):

# to jest plik a.dat
# obliczenia dla E= 0.12  Sigma= 8
# x y z
1.1 12.21 -9
2.2 22.23 -8
3.4 34.34 -7

# plik b.dat, dla E= 0.13  Sigma= 9
1.11 112
2.2  256
3.40 301

Przykładowe operacje na nich:
Ad 1)
--> zebrać wszystkie linie razem:
1.1 12.21 -9
2.2 22.23 -8
3.4 34.34 -7
1.11 112
2.2  256
3.40 301
--> wybrać linie z wartością > 30 w drugiej kolumnie:
3.4 34.34 -7
1.11 112
2.2  256
3.40 301
--> wypisać 2 kolumnę z linii o wartości w pierwszej kolumnie równej 3.4:
34.34
301

Ad 2)
--> wypisać wartości z 2-ej kolumny zebrane wg wartości w 1-ej kolumnie:
1.1 12.21 --
1.11 -- 112
2.2 22.23 256
3.4 34.34 301
--> wypisać wartości z 1-ej kolumny zebrane wg kolejności wystąpienia:
1.1 1.11
2.2 2.2
3.4 3.40
--> wypisać 2-gą kolumnę podając wartość parametru E w pierwszej, pod warunkiem, że wartość w 1-ej kolumnie jest z zakresu 2.0 a 3.0:
0.12 22.23
0.13 256
--> wypisać wartość parametrów E i R, bez wypisywania żadnych kolumn:
0.12 8
0.13 9

Ad 3)
--> wypisać 1-szą kol. oraz sumę, średnią i liczbę danych branych z 2-ej kolumny:
1.1  12.21  12.21  1
1.11 112    112    1
2.2  278.23 139.12 2
3.4  335.34 167.67 2

Ad 4) --> zamienić kolumnę 1-szą i 2-gą w plikach *.dat - wynikiem mają być zmienione pliki a.dat i b.dat :

# to jest plik a.dat
# obliczenia dla E= 0.12  Sigma= 8
# x y z
12.21 1.1 -9
22.23 2.2 -8
34.34 3.4 -7

# plik b.dat, dla E= 0.13  Sigma= 9
112 1.11
256 2.2
301 3.40



Uwagi końcowe
-------------
- liczby traktować przetwarzać jako liczby, a nie tekst (żeby się nie okazało, że 1.0, 1, 1. oraz 1e0 to różne wartości...); na wyjściu format może się zmienić w stosunku do oryginalnego - np. w przykładach 3.40 może się zamienić na 3.4 i to będzie poprawne
- jeśli zadanych jest kilka operacji/warunków, na należy je wykonać w takiej kolejności, w jakiej zostały wymienione przy podawaniu opcji do programu
- napisanie dokumentacji użytkownika lepiej zostawić na koniec, jak już się ostatecznie ustalą nazwy parametrów linii poleceń
- na wyjściu używać kropki jako "przecinka dziesiętnego", zakładać to samo na wejściu

