Powrót

Pora wrócić do pisania pracy magisterskiej.

Na jakim etapie jestem?

Wykonałem testy. Każdy test generuje dużą ilość obrazów. Zajmują one w sumie 140 GB.
Niektóre obrazy wykorzystałem do stworzenia gifów, które przedstawiają etap budowania harmonogramu. Trochę zajęło mi usprawnienie procesu tworzenia gifów: zdjęcia są ciężkie, programy do tworzenia gifów nie są często darmowe, a te darmowe tworzą gifa bardzo długo. Rozwiązanie okazało się bardzo proste. Nie tworzę plików z rozszerzeniem .gif. Używam do pisania pracy systemu LaTex. Umożliwia on zagnieżdżanie w pdfie właśnie gifów. Prawie zero pracy – kod generujący gifa jest bardzo podobny do tego, który wstawia zdjęcie.

Co zostało do zrobienia? Napisać tekst. Dużo tekstu. Wybrać odpowiednie zdjęcia, wykresy, tabele. A zatem, do dzieła!

Nazywaj zmienne mądrze

Zapewne nieraz słyszałeś lub czytałeś, aby pisać czysty i samokomentujący się kod. Jak mantrę słyszysz: używaj znaczących nazw dla zmiennych, nazywaj zmienne mądrze, nie używaj słów: foo, bar, a jednoliterowe nazwy zmiennych zachowaj tylko dla indeksów w trywialnych pętlach. Wydaje mi się, że programista piszący kod, który dzisiaj poprawiałem, zapomniał o jednym: nazwy nie mogą kłamać!

W wyżej wspomnianym programie mam grupę elementów, która ma jeden nagłówek. Użytkownik wykonuje na nich różne operacje. Jest pewna operacja, która jeśli jest wykonana na elemencie grupy niebędącym nagłówkiem, to zostanie ona również wykonana na nagłówku tej grupy.

Wszystkie elementy z grupy wyświetlane są użytkownikowi w tabeli. W zależności od kryteriów, w tabeli mogą znajdować się elementy z wielu grup, ale również może być tak, że nie wyświetlone są wszystkie elementy z konkretnej grupy.

Wejdźmy głębiej w szczegóły naszej operacji:

  1. Wykonaj operację X na elemencie grupy
  2. Jeśli element nie jest nagłówkiem, to zacznij próbę wykonania operacji X dla nagłówka, w tym celu:
    1. Znajdź nagłówek
    2. Jeśli znalazłeś nagłówek wykonaj operację X
  3. Koniec algorytmu

Wszystko ładnie i pięknie, ale… w punkcie 3 nie znajduje nagłówka. Dlaczego? Program nie szuka nagłówka w bazie danych, ale w naszej tabeli, która np. (przez odpowiednie kryteria) wyświetla tylko jeden wiersz, który właśnie przerobiliśmy w punkcie pierwszym.

Cóż, bug jak bug, trzeba poprawić. Szybko dopisuję więc kilka linii: jak nie znajdujesz w tabeli nagłówka, to poszukaj go w bazie danych i jak go masz, to wykonaj na niej zadaną operację. Biorę klasą odpowiedzialną za pobieranie danych. Jest nawet zaimplementowana funkcja, która zwróci mi tabelę zawierającą elementy grupy i jako parametr przyjmuje id takiego elementu (nagłówek też jest elementem grupy).

F5 i zaczynamy testować. Nic się niestety nie zmieniło. Nagłówek nie został przetworzony…. Aplikacja stop, breakpoint i F6. Jestem. Mam id nagłówka, uruchamiam funkcję pobrania z bazy danych i… dostaję nulla. Jakim cudem? Nie może być!

Wchodzę w ciało funkcji. W skrócie funkcja ta jest adapterem i wywołuje kolejną funkcję. Wchodzę w nią i… ta funkcja nie przyjmuje już jako parametru id elementu, ale całej grupy….

Programisto, nazywaj zmienne mądrze, nazywaj zmiennie poprawnie i nie oszukuj :) (a jak refaktoryzujesz, to rób to z głową, nie tylko testy muszą świecić się na zielono)

Aktualna baza danych

Baza danych została zaktualizowana. Zmieniłem nazwy tabel i kolumn, dodałem relacje, usunąłem niepotrzebne kolumny. Zostawiłem stare nazwy, nowe wyglądają następująco: stara_nazwa_nowa_nazwa. Tabele służące tworzeniu relacji wiele do wielu nazwałem zgodnie z formatem: tabela1_AND_tabela2.

Poniższy diagram przedstawia nową strukturę bazy danych.

database

Bazę danych tworzy 15 tabel:

  1. ElectricityBorders – tabela przedstawia limit prądu, zaplanowane zużycie oraz różnice między tymi wartościami na dany dzień oraz czas.
  2. Equipments – tabela zawiera informację o przynależności konkretnego gniazdka. W pierwotnej wersji zawierało informację o wyposażeniu sali (np. komputer, rzutnik). Obecnie zawiera informację o tym, do którego budynku należy gniazdko poprzez symbol budynku.
  3. Group_Plugs – tabela zawiera informacje o wtyczkach urządzeń. W pierwotnej wersji studenci należeli do konkretnych grup dydaktycznych. Obecnie urządzenia przynależą do konkretnych wtyczek. Założono, że jedno urządzenie ma tylko jedną własną wtyczkę.
  4. Plan – tabela przedstawia plan używania wtyczek urządzeń z użyciem konkretnego gniazdka w konkretnym dniu i czasie.
  5. Properties – tabela przechowuje informacje o parametrach systemu, jak np. ilość dni, liczbę okresów, na którą podzielona jest doba.
  6. RejectGroup_Plugs – tabela zawiera wtyczki (pierwotnie grupy), które zostały odrzucone w fazie planowania.
  7. Room_Socket_And_Equipment – tabela wiele do wielu łącząca gniazdka (pierwotnie sale) z ich przynależnością do budynku (wyposażeniem).
  8. Room_Sockets – tabela przedstawia dane o gniazdkach (pierwotnie sale).
  9. Student_User_And_Group_Plug – tabela wiele do wielu między właścicielami budynków a wtyczkami (pierwotnie relacja przynależności studentów do grup).
  10. Student_Users – tabela przedstawia dane o właścicielach wtyczek, a przez relację jeden do jednego z urządzeniami, są to właściciele tychże urządzeń (pierwotnie byli to studenci należący do konkretnych grup. Mogło być wielu studentów w jednej grupie, teraz wtyczka ma tylko jednego właściciela).
  11. Subject_Building_And_Equipment – tabela z relacją wiele do wielu między symbolem budynku a budynkiem (pierwotnie każdy przedmiot miał wymagania, np. Podstawy programowania – laboratorium wymagało komputerów w sali).
  12. Subject_Buildings – tabela przechowujące informacje o budynkach (pierwotnie przedmiotach).
  13. Subject_BuildingTypes – tabela z typami budynków, np. administracja, dom, (pierwotnie typy przedmiotów, np. wykład, ćwiczenia).
  14. Teacher_Device_And_Group_Plug – tabela przechowująca relację między urządzeniem a wtyczką (pierwotnie zawierała informację o grupach, które prowadził konkretny nauczyciel).
  15. Teacher_Devices – tabela z informacjami o urządzeniach (pierwotnie o nauczycielach). Znajdują się tu m.in. informacje o predyspozycjach uruchomienia (np. drugiego dnia). Pierwotnie był tu dane o wykładowcach.

Baza danych

W ramach zaadaptowania algorytmu układającego plan zajęć na uczelni do problemu harmonogramu urządzeń została trochę zmieniona baza danych. Przedstawia ją poniższy obrazek:

DatabaseDiagram

Dodano tabelę ElectricityBorder, która zawiera informację o ograniczeniu na prąd w danym dniu oraz czasie, przechowuje również wykorzystany już w tym czasie prąd oraz różnicę między tymi wartościami.

Tabela Teachers została rozszerzona o kolumnę electricity_value – wartość prądu, jaką zużywa nauczyciel.

Definicje tabel uległy zmianom. Można to zauważyć obserwując ich nazwy:

  • Tabela Teachers zmieniła się na Teachers_Devices – wiersze tabeli reprezentują konkretne urządzenie.
  • Groups -> Groups_Plugs – tabela reprezentuje wtyczkę urządzenia.
  • TeachGroup -> Teach_DeviceGroup  – relacja wiele do wielu dla tabeli Teachers_Devices  i Groups_Plugs, odpowiednio dodawane dane sprawią jednak, że ta relacja będzie 1-1.
  • SubjectTypes -> Subject_BuildingTypes – tabela zawiera typy budynków. W moim przypadku będą dwa typy: Administracja i Dom. Mają one różne priorytety w algorytmie układania harmonogramu.
  • Subjects -> Subjects_Buildings – wiersze tabeli reprezentują konkretne budynki na osiedlu.
  • Rooms -> Rooms_SocketHouses – wiersze reprezentują konkretne gniazdka.
  • Students – Students_Users -> tabela zawiera wpisy z konkretnymi użytkownikami konkretnego urządzenia.

Pozostałe tabele nie zmieniły pierwotnej funkcji swojego działania, więc ich nazwy też nie uległy zmianom.

Agent planner

W celu ułożenia harmonogramu dla urządzeń wykorzystuję kod źródłowy układający plan zajęć na Politechnice Gdańskiej. Kod ten stanowi pracę magisterską Rafała Tkaczyka. Oparty jest on o agentów programowych (zaimplementowanych w technologii JADE) oraz relacyjnej bazie MySQL. Poniższy rysunek przedstawia pierwotny model bazy danych:

databaseDiagram

Stan projektu

W trakcie tworzenia mojej pracy magisterskiej dotarłem do momentu stworzenia i zaimplementowania algorytmu tworzenia harmonogramu dla urządzeń bazujący na agentach programowych. Wykonałem jego okrojoną wersję, która wymagała jeszcze wiele pracy. Niespodziewanie mój promotor uszczęśliwił mnie działającym algorytmem rozwiązującym problem tworzenia harmonogramu zajęć na Politechnice Gdańskiej, który bazuje na agentach programowych.

Kod napisany jest w Javie i również korzysta z biblioteki JADE. Wykorzystuje on jednak relacyjną bazę danych MySQL. To jednak nie jest żaden problem. Zainstalowałem bazę danych, zmieniłem trochę otrzymany kod, aby działał na mojej maszynie, i po chwili miałem ułożony harmonogram dla uczelni gdańskiej.

Z otrzymanym rozwiązaniem zrobiłem kilka rzeczy:
– wykorzystałem moją klasę uruchamiającą agentów,
– scenariusz dla konkretnego problemu zapisałem w kodzie, a następnie zapisuję ten scenariusz w XMLu,
– usunąłem szkielet mojego algorytmu,
– rysuje wykresu dla planu w kontekście włączania urządzeń i zużywania prądu,
– w momencie uruchamiania środowiska agentów, usuwam dane z bazy danych i wczytuję wszystko z XMLa.

Obecnie jestem w momencie implementowania przystosowania modelu bazy danych z problemu uczelni na model z problemu osiedla.

Architektury systemów wieloagentowych

Jorg P. Muller w Control Architectures for Autonomous and Interacting Agents: A Survey wymienia architektury systemów wieloagentowych:

  1. Dla agentów reaktywnych:
    1. Broks: subsumpcja architektury – jest to dekompozycja systemu na aktywnych agentów będących producentami, którzy pracują równolegle.
    2. Steels: roboty  behawioralne – stawianie na samoorganizujący się świat, gdzie agenci składają się z obiektów, które mają wykonywać proste zadania (swarm intelligence).
    3. Arkim: architektura AuRA (Autonomous Robot Architecture) – rozszerza model Brooks’a o pięć komponentów. Jest podobny do Procedural Reasoning System oraz Firby’s RAP System.
    4. Maes: dynamiczny wybór – agent decyduje (dynamicznie) jaką akcję wykona w następnym momencie swojego życia.
  2.  Dla agentów deliberatywnych (naradzających się)
    1. Bratman: IRMA – architektura agentów ograniczonych zasobami. Opisuje jak agent wybiera swój kierunek działania na podstawie swoich doznań, wierzeń, pragnień i intencji.
    2. Rao i Georgeff: formalny model BDI – sformalizowany model BDI. Wierzenia, pragnienia i intencje opisywane są przez operatory modalne.
    3. Rao i Georgeff:interpretacja BDI – dodanie interpretera, który interpretuje BDI agentów, ponieważ wcześniej model mógł nie mieć pełnej listy aksjomatów.
    4. Shoham i Thomas: programowanie zorientowane na agentów – architektura AOP (Agent-oriented programming). Przedstawili agenta jako jeden obiekt, który posiada wierzenia, możliwości, wybory i zobowiązania.
  3. Dla agentów interaktywnych:
    1. Fisher: MAGSY – agenta reprezentuje zestaw faktów będący jego wiedzą, zestaw zasad będących strategia i zachowaniami, zestaw serwisów będących interfejsem zewnętrznym agenta. Jeden agent może zawołać serwis innego agenta.
    2. Jennings: GRATE – zawiera warstwę wiedzy powszechnej (znanej i dostępnej dla każdego agenta)
    3. Steiner: MECCA – agent składa się z ciała (aplikacja), głowy (cele agenta), komunikatora.
    4. Sundermeyer: COSY – opisuje agenta jako zachowania, zasoby i intencje
  4. Architektury hybrydowe.

Refaktoryzacja

Refaktoryzacja – z pewnością każdy, kto napisał już trochę kodu, zna to słowo.

W tym roku już drugi raz trafiła w moje ręce książka:

Refaktoryzacja. Ulepszanie struktury istniejącego kodu. Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts.

Bardzo polecam tę książkę. Osobiście dużo czasu poświęcam refaktoryzacji. Wynika to ze sposobu tworzenia przeze mnie oprogramowania: mało modelowania w początkowej fazie, najpierw zróbmy coś działającego, potem to uporządkujmy. Z czasem i doświadczeniem nie poświęcam wcale więcej czasu na modelowanie, lecz od razu tworzę lepsze modele. Często przez kilka dni nie tworzę żadnej wartości dodanej, prócz tego, że mój kod jest przejrzystszy, lżejszy i bardziej logiczny. Dlaczego to robię? Sprawia mi to przyjemność i daje sporo satysfakcji. Zabawne jest, gdy czytasz swój stary kod i myślisz sobie: kto to napisał?

Jak zabieram się do refaktoryzacji?

Robię to na trzy sposoby:

Przede wszystkim czytam kod i używam przekształceń z wyżej wymienionej książki.

Do mojego kodu piszę często dokumentację. Pisząc ją, można łatwo zauważyć, że coś z naszym kodem może być nie do końca w porządku.

Bardzo przydatne w procesie refaktoryzacji są diagramu UML: diagramy klas oraz przepływu. Daje nam to szerokie spojrzenie na tworzone oprogramowanie.

Zmiany

Po wielu napisanych linijkach kodu i rozmowach z promotorami, moja praca magisterska nabrała kształtów oraz nowego kierunku. Jej temat nie uległ zmianie, lecz jej zawartość.

Czego dotyczy aktualnie? Jaki problem chcę rozwiązać?

Problem stworzenia harmonogramu użycia urządzeń w taki sposób, aby funkcja ich zakumulowanego zużycia prądu miała jak najmniej skoków. Co mam na myśli? Nie chcę, aby wykres tej funkcji rwał się i aby nie miał nagłych skoków lub spadków.

Dla wyjaśnienia mały przykład:

Mamy dwa urządzenia:

Pralka – chcemy, aby pranie było zrobione we wtorek między 16 a 20 lub w środę między 14 a 20 (preferencje działania). Ma to być jedno pranie o czasie trwania 2h (sesja). Ma moc 200 W.

Piec – ma działać cały czas między godziną 6 a 18. Ma moc 800 W.

Najlepszym  rozwiązaniem, wedle moich powyższych kryteriów, jest włączenie pieca codziennie między 6 a 18 oraz pralki w środę o godzinie 16.

Gdybyśmy włączyli pralkę w innym momencie, to w stosunku do zaproponowanego wyżej rozwiązania, mielibyśmy jeden spadem z 200 W do 0 W oraz jeden skok z 0 W do 800 W. Ja proponuję zamiast tego jeden skok z 200 W na 800 W.

Problem stabilizacji i skalowania systemu wieloagentowego

Systemy agentowe, w których zmienia się w czasie liczba aktualnie działających agentów, borykają się z problemem stabilizacji oraz skalowalności.
Problem stabilizacji – liczba agentów w systemie zmienia się w czasie, jednak stabilność systemu wymaga, aby ich liczba była ograniczona. Ograniczenie to powinno definiować nie tylko maksymalną liczbę agentów, ale również minimalną.
Problem skalowalności – problem polega na dobraniu odpowiedniej liczby agentów do wielkości zadania. Podejście agentowe umożliwia precyzyjniejsze skalowanie dzięki doborowi odpowiedniej ilości agentów konkretnego typu. Zbyt wielka liczba agentów może sprawić, że zasoby maszyny (pamięć, czas procesora) są w głównej mierze przeznaczane na podtrzymywanie przy życiu agentów, a nie na ich pracę.
Jak radzić sobie z tymi problemami? W celu poradzenia sobie z powyższymi problemami, trzeba zająć się poniższymi kwestiami:
Utrzymanie minimalnej liczby agentów – należy utrzymać minimalną liczbę agentów, którzy mogą generować agentów.
Ograniczenie maksymalnej liczby agentów:
  • Liczba niektórych agentów może być stała.
  • Usuwać nadmiarowych agentów:
    • Droga samolikwidacji agenta, np. poprzez energię życiową agenta zwiększaną za każdym sukcesem, a zmniejszaną z czasem oraz przez porażkę.
    • Droga likwidacji agenta przez inne agenty – należy zidentyfikować agentów, którzy są nadmiarowi:
      • Ustalić kryterium identyfikacji agentów do usunięcia.
      • Ustalić ilu agentów należy usunąć.
Np. ustalamy ilu jest agentów danego typu i ilu chcemy ich usunąć, a następnie usuwamy ich losowo lub tych z najmniejszą energią życiową.
Ograniczenie liczby generowanych agentów – można wyposażyć agenta generującego innych agentów w mechanizm określający celowość generowania nowego agenta. Mechanizm powinien uwzględniać:
  • Potrzebę generacji, która wynika z konieczności zapewnienia konkretnej funkcjonalności.
  • Ocenę możliwości generacji wynikającej z oceny chwilowej liczby agentów danego typu i potrzebnych zasobów.
Agent generujący powinien zatem obserwować otaczające go środowisko.
Koncepcja agentów bezrobotnych – można wprowadzić agentów, którzy poszukują zadań do wykonania (są bezrobotni), a następnie przekwalifikować ich w konkretny typ agenta, który może wykonać znalezione zadanie. Po wykonaniu zadania agent znowu staje się bezrobotny [2].

[2] Cetnarowicz K. – Paradygmat agentowy w Informatyce. Koncepcje, podstawy i zastosowania. Wydawnictwo Akademicka Oficyna Wydawnicza EXIT, Warszawa 2012.