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.

Klasyfikacja systemów agentowych

Ze względu na własności środowiska, możemy rozróżnić agentów na:

  • Mobilnych agentów softwaerowych – jeśli środowisko jest cyberprzestrzenią, to agenci są agentami softwaerowymi.
  • Agentów upostaciowionych – jeśli środowisko jest przestrzenią rzeczywistą, to agenci mogą być wbudowani w roboty mobilne.

Ze względu na złożoność środowiska, którego świadomy jest agent, można wyróżnić następujących agentów:

  • Agent reaktywny – w tym przypadku środowisko zrealizowane jest w oparciu o automat skończony.
  • Agent kognitywny –  środowisko jest bardziej złożone oraz agent uwzględnia innych agentów.
  • Agent deliberatywny – środowisko jest złożone, agent dostrzega innych agentów oraz jest świadomy swego istnienia [2 str. 77-78].

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

Środowisko agenta

Agent osadzony jest w konkretnym środowisku. Może on czerpać z niego informacje o jego stanie (obserwować) oraz wpływać na nie. Ze względu na dostępność środowiska dla konkretnego agenta, może podzielić je na części:

  • Środowisko dalekie (całe środowisko) – zbiór elementów środowiska, które są w bezpośrednim lub pośrednim zasięgu obserwacji przez agenta. W ramach obserwacji pośredniej, agent zmuszony jest wykonać dodatkowe akcje w celu uzyskania informacji. Do takich akcji mogą należeć m. in. przemieszczenie się, zapytanie innego agenta.
  • Środowisko bliskie – zbiór elementów środowiska, które są w bezpośrednim zasięgu obserwacji agenta.
  • Otoczenie – część środowiska bliskiego, które jest również w zasięgu możliwości sprawczych agenta.
  • Sąsiedztwo – część otoczenia, na którą agent może oddziaływać posiadając do tego większe uprawnienia, niż pozostali agenci.
  • Środowisko własne – część sąsiedztwa, na którą oddziaływać może wyłącznie agent – właściciel tego środowiska. Inni agenci mogą również wpływać na to środowisko, ale wyłącznie za pozwoleniem właściciela i za jego pośrednictwem [2 str. 60].

Proponowany podział nie zawiera jednak elementów środowiska, na które może wpływać dany agent, ale których nie może obserwować.

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

Przepływ informacji w systemie wieloagentowym

W systemie wieloagentowym można wyróżnić dwie grupy w przepływie informacji:

  • Agent – agent – agenci komunikują się między sobą poprzez stworzone kanały komunikacji. Agent może adresować swoją informację do konkretnego agenta. Komunikacja ta może mieć również określony cel. Mogą oni prowadzić konwersacje o określonych wątkach.
  • Agent – środowisko:
    • Ze środowiska – agent obserwuje środowisko i  jego stan (w tym również działania innych agentów).
    • Do środowiska – agent oddziałuje na środowisko poprzez swoje zachowanie, które to środowisko w jakiś sposób zmienia [2 str. 59].

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

Kim jest agent?

Cytując M. Wooldridge’a:

Agent jest systemem komputerowym, który jest osadzony w pewnym środowisku, i który jest zdolny do autonomicznych akcji w celu zrealizowania zleconych, określonych celów[1].

Podejście programowania agentowego jest wyższym poziomem abstrakcji od programowania obiektowe. Od obiektów odróżnia go kilka elementów (m. in. tolerancja na błędne dane, dublowanie obliczeń, zwracanie wyników obarczonych błędem). K. Cetnarowicz wymienia cechy agenta programowego:

  • Własność autonomii nie jest cechą odróżniającą pojęcie agenta od innych pojęć z zakresu informatyki, a w szczególności od pojęcia obiektu, który podobnie jak agent może być rozważany jako autonomiczny.

  • Cechą wyróżniającą agenta jest jego zdolność do obserwacji zachowania się innych agentów w środowisku.

  • Agent może posiadać zdolność do komunikacji z innymi agentami za pośrednictwem środowiska, ale także bezpośredniej komunikacji (podobnej do komunikacji między obiektami), ale zdolność ta nie jest cechą wyróżniającą dla agenta w odniesieniu do obiektu [2 str.48-49].

Podsumowując, agenci w tworzonym systemie będą charakteryzowali się następującymi cechami:

  • Autonomiczność.
  • Komunikatywność.
  • Obserwowanie środowiska i innych agentów.
  • Reagowanie na zmiany środowiska i działania innych agentów.
  • Zdolność do uczenia się i wykorzystywania wiedzy.
  • Tolerancja na błędy danych oraz na ich brak.
  • Zwracanie nie zawsze dokładnych danych (mogą być one błędne).

[1] Wooldridge M. – An Introduction to MultiAgent Systems. John Wiley and sons Ltd., 2009.

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

Scenariusze – opał

System powinien móc obsługiwać osiedle w zmiennych warunkach środowiska. Poniżej prezentuję kilka przykładowych scenariuszy:
Warunki:

  • Czas trwania symulacji: 1 rok, 3 lata, osiedle nie wie jednak jak długo trwać będzie symulacja, dlatego też na koniec symulacji magazyny nie będą puste, a wszystkie obiekty wyprzedane,
  • Budżet: nieograniczony,
  • Wymagane: utrzymanie temperatury na poziomie {21^\circ C \pm 3^\circ}C,
  • Działania systemu:
    • Zakup pieców oraz opału,
  • Oczekiwane rezultaty:
    • Utrzymanie wymaganej temperatury przez okres symulacji oraz zminimalizowanie kosztów przeznaczonych na opał.
  • Porównanie:
    • wyniki zostaną porównane z podejściem zakupu przez algorytm zachłanny (zakup najtańczego pieca w przeliczeniu na generowane ciepło, całkowite wypełnienie magazynu potrzebnym opałem).

Prosty

  • Dane wejściowe:
    • Możliwy zakup:
      • Grzejnik,
      • Czujnik temperatury,
      • Grzejnik elektryczny do podgrzewania wody,
      • Grzejnik elektryczny,
      • Prąd,
      • Woda,
      • Ciepła woda,
      • Piec gazowy,
      • Licznik gazu,
      • Gaz,
      • Olej opałowy,
      • Węgiel,
      • Zbiornik na olej opałowy,
      • Piec na olej opałowy,
      • Piec węglowy,
  • Dane historyczne:
    • informacje o najwyższej i najniższej temperaturze w przeciągu ostatnich 10 lat,
    • historyczne zapotrzebowanie na ciepłą wodę,
  • Zmiany środowiska:
    • Prognozy pogody na najbliższe 3 dni ze sprawdzalnością rzędu 98% generowane co pół dnia,
    • Prognozy pogody na najbliższe 7 dni ze sprawdzalnością rzędu 73% generowane co pół dnia,
    • Wyższy koszt (120%) węgla w okresie jesienno-zimowym,

Średni

Scenariusz rozbudowany jest o możliwość ocieplenia budynku oraz cena gazu z każdym miesiącem rośnie o 0,5% podstawowej ceny gazu . W systemie są również Ekspres do kawy, pralka oraz zmywarka, które są losowo włączane.

Złożony

System w tym przypadku zarządza kiedy włączać, które urządzanie wykorzystujące ciepłą wodę lub ciepło. Środowisko generuje przerwy w dostawie mediów. Liczba obiektów możliwych do zakupu jest ograniczona. Możliwa jest sprzedaż posiadanych rzeczy (po niższych cenach).

Cassandra i logi

Podłączyłem do mojego rozwiązania bazę danych Cassandra, korzystając ze sterownika Java Driver 2.1 for Apache Cassandra. Dodałem również logowanie do pliku korzystając z Log4j oraz tutorialu.

Najpierw zainstalowałem Cassandrę oraz DevCenter. Następnie stworzyłem interfejs, który wykorzystywać będę do obsługi bazy danych:

package karol_bocian.solution.databaseAccess;

import com.datastax.driver.core.Session;

public interface IDatabaseConnector {
    void Connect(String node);
    void Close();
    Session GetSession();
    void CreateKeyspace(String keyspace);
    void DropKeyspace(String keyspace);
}

Implementuje go klasa:

package karol_bocian.solution.databaseAccess;

import com.datastax.driver.core.*;
import org.apache.log4j.Logger;

public class DatabaseConnector implements IDatabaseConnector {
    private static final Logger logger = Logger.getLogger(DatabaseConnector.class.getName());
    private Cluster cluster;
    private Session session;

    @Override
    public void Connect(String node) {
        cluster = Cluster.builder()
                .addContactPoint(node)
                .build();
        cluster.getConfiguration()
                .getProtocolOptions()
                .setCompression(ProtocolOptions.Compression.LZ4);
        LogInfos();
        session = cluster.connect();
    }

    private void LogInfos() {
        Metadata metadata = cluster.getMetadata();
        logger.info(String.format("Connected to cluster: %s", metadata.getClusterName()));
        for (Host host : metadata.getAllHosts()) {
            logger.info(String.format("Data center: %s; Host: %s; Rack: %s",
                    host.getDatacenter(), host.getAddress(), host.getRack()));
        }
    }

    @Override
    public void CreateKeyspace(String keyspace) {
        session.execute("CREATE KEYSPACE IF NOT EXISTS " + keyspace + " WITH replication " +
                "= {'class':'SimpleStrategy', 'replication_factor':1};");
    }

    @Override
    public void DropKeyspace(String keyspace) {
        session.execute("DROP KEYSPACE " + keyspace + ";");
    }

    @Override
    public void Close() {
        session.close();
        cluster.close();
    }

    @Override
    public Session GetSession() {
        return this.session;
    }
}

W tej klasie łączymy się za pomocą metody Connect do klastra o zadanym adresie (node). Metoda CreateKeyspace tworzy zadany keyspace, zaś DropKeyspace usuwa go. Metoda LogInfos wyświetla informacje o klastrze. Po skończonej pracy musimy zamknąć połączenie z bazą. Implementuje to metoda Close.

Do logowania służy metoda:

logger.info(String.format("Connected to cluster: %s", metadata.getClusterName()));

Możliwe  jest logowanie informacji, ostrzeżeń, błędów, informacji do debugu itp.

Zmieniłem klasę Main:

package karol_bocian.solution;

import karol_bocian.solution.databaseAccess.DatabaseConnector;
import karol_bocian.solution.databaseAccess.IDatabaseConnector;

public class Main {
  private static String node = "127.0.0.1";
  private static String keyspace = "agents";

  public static void main(String[] args) {
    IDatabaseConnector databaseConnector = new DatabaseConnector();
    databaseConnector.Connect(node);
    databaseConnector.CreateKeyspace(keyspace);
    databaseConnector.Close();
 }
}

Do resources dodałem również plik log4j.properties, w którym zapisałem ustawienia logowania:

# Root logger option
log4j.rootLogger=DEBUG, stdout, file

# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Redirect log messages to a log file, support file rolling.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=D:\\logs.log
log4j.appender.file.MaxFileSize=50MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

Utworzyłem również pusty plik tekstowy D:\\logs.log.

Logi zapisywane są do tego pliku. Wyświetlane są również na konsoli.

Zarządzanie agentami

Wraz z pracami projekt przyjął nową strukturę:

struk

W celu zarządzania tworzeniem agentów stworzyłem interface: IAgentManager:

package karol_bocian.solution.agentModule.agentManagement;

public interface IAgentManager {
    void RunAgents();
}

oraz klasę AgentManager implementującą powyższy interfejs:

package karol_bocian.solution.agentModule.agentManagement;

import java.util.Map;

public class AgentManager implements IAgentManager {

    private final String packageName = "karol_bocian.solution.agentModule.agents.";
    private String agentsList = "";

    public AgentManager(Map<String, String> agentsMap) {
        BuildAgentsList(agentsMap);
    }

    private void BuildAgentsList(Map<String, String> agentsMap) {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, String> entry : agentsMap.entrySet()) {
            stringBuilder.append(entry.getKey());
            stringBuilder.append(":");
            stringBuilder.append(packageName);
            stringBuilder.append(entry.getValue());
            stringBuilder.append(";");
        }
        agentsList = stringBuilder.toString();
    }


    @Override
    public void RunAgents() {
        JadeBootThread jadeBootThread = null;
        try {
            jadeBootThread = new JadeBootThread(agentsList);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        jadeBootThread.run();
    }
}

Służy ona do tworzenia agentów. Należy w konstruktorze tej klasy przekazać listę agentów w postaci krotek: <„imięAgenta”,”klasaImplementującaAgenta”> zapisanych w obiekcie Map. Klasa AgentManager przetwarza Mapę tworząc odpowiednie polecenie z listą agentów i używając go woła w metodzie RunAgents opisywany już JadeBootThread.

Zmianie uległa również klasa Main. Zawiera ona metodę, w której precyzujemy listę tworzonych agentów (PrepareAgentList).

package karol_bocian.solution;

import karol_bocian.solution.agentModule.agentManagement.AgentManager;
import karol_bocian.solution.agentModule.agentManagement.IAgentManager;

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        IAgentManager agentManager = new AgentManager(PrepareAgentList());
        agentManager.RunAgents();
    }

    private static Map<String, String> PrepareAgentList() {
        Map<String, String> agentsMap = new HashMap<>();
        agentsMap.put("AgentTomek", "HelloAgent");
        return agentsMap;
    }
}