Professional Documents
Culture Documents
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Wydawnictwo Helion
ul. Kociuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl
Java. Programowanie,
biblioteki open-source
i pomysy na nowe projekty
Autor: Brian Eubanks
Tumaczenie: Grzegorz Borkowski
ISBN: 83-246-0624-6
Tytu oryginau: Wicked Cool Java: Code Bits,
Open-Source Libraries, and Project Ideas
Format: B5, stron: 248
Odkryj nieznane moliwoci Javy
Sieci semantyczne i neuronowe
Przetwarzanie grafiki i multimediw
Obliczenia naukowe
Java, mimo stosunkowo krtkiej obecnoci na rynku, staa si jednym z najpopularniejszych
jzykw programowania. Codziennie korzystaj z niej setki tysicy programistw z caego
wiata. Najwiksze korporacje wiata za jej pomoc buduj systemy informatyczne
przetwarzajce potne porcje danych. Aplikacje bazodanowe, serwlety i aplety to
najbardziej znane zastosowania Javy, jednak nie jedyne. W sieci dostpna jest ogromna
ilo bibliotek tworzonych przez pasjonatw, ktrzy wykorzystuj Jav do odmiennych
celw, takich jak przetwarzanie grafiki, modelowanie sieci neuronowych,
przeprowadzanie zoonych oblicze i wielu innych zada.
Dziki ksice Java. Programowanie, biblioteki open-source i pomysy na nowe projekty
poznasz mniej znane zastosowania Javy. Dowiesz si, jak za pomoc bibliotek
dostpnych na licencji open-source tworzy ciekawe projekty i pisa nietypowe aplikacje.
Nauczysz si przetwarza pliki XML i HTML, obrabia i generowa grafik a take
wywietla pliki multimedialne. Przeczytasz o sieciach semantycznych i neuronowych,
odczytywaniu kanaw RSS i sterowaniu urzdzeniami podczonymi do komputera.
Nieznane funkcje standardowego API Javy
Przetwarzanie acuchw tekstowych
Analiza plikw XML i HTML
Stosowanie RDF w projektach
Czytanie kanaw RSS
Obliczenia o dowolnej precyzji
Realizacja algorytmw genetycznych
Symulowanie sieci neuronowych
Generowanie plikw SVG
Wsppraca z interfejsem MIDI
Jeli lubisz eksperymentowa z jzykami programowania,
ta ksika bdzie dla Ciebie doskonaym rdem inspiracji
PODZIKOWANIA ...................................................................................... 9
WSTP ....................................................................................................... 11
1
STANDARDOWE API JAVY ....................................................................... 15
Uycie nowej wersji ptli for .................................................................................................16
Wykorzystanie konstrukcji enum ...........................................................................................18
Mapy bez rzutowania w d ...................................................................................................21
Pisanie metod z parametrami generycznymi .........................................................................22
Metody ze zmienn liczb parametrw .................................................................................25
Asercje w Javie .......................................................................................................................27
Uycie System.nanoTime .......................................................................................................29
Upienie wtku na czas krtszy od milisekundy ....................................................................30
Klasy anonimowe ...................................................................................................................31
Porwnania == != .equals ...................................................................................................33
Podsumowanie .......................................................................................................................35
2
NARZDZIA DO PRACY Z ACUCHAMI TEKSTOWYMI ....................... 37
Uycie wyrae regularnych do wyszukiwania tekstw ........................................................38
Uycie metody String.split .....................................................................................................40
Wyszukiwanie fragmentw w acuchach tekstowych ..........................................................41
Uycie grup w wyraeniach regularnych ................................................................................42
Wykonywanie zamiany tekstw za pomoc wyrae regularnych ........................................44
Przetwarzanie z uyciem klasy Scanner .................................................................................47
Analiza skomplikowanej skadni przy uyciu klasy Scanner ....................................................49
Generowanie przypadkowego tekstu ....................................................................................51
Drukowanie zawartoci tablic w Javie 1.5 ..............................................................................52
Kodowanie i dekodowanie danych binarnych ........................................................................54
Spis treci
Spis treci
Spis treci
.
ZADZIWIAJCY JEST FAKT, E W WIELU KRGACH NAUKOWYCH
FORTRAN WCI SPRAWUJE NIEPODZIELN WADZ (WIEM, WIEM, TE
MNIE TO PRZERAA). PRZYCZYN TEGO STANU RZECZY NIEKONIECZNIE
jest to, e Fortran jest wspaniaym jzykiem programowania, lecz raczej
fakt, e jego standardowe biblioteki dostarczaj ogromny zbir operacji matematycznych, z ktrych korzysta wielka rzesza istniejcych programw. Java istnieje
od ponad dekady, dziaa na wikszej liczbie dostpnych platform, ma standardowe
API o bogatszych moliwociach i pozwala robi rzeczy niemoliwe w Fortranie. Dlaczego wic Java nie jest tak popularna w aplikacjach dla nauk cisych? Wynika to by moe z faktu, e Java nie posiada dobrych bibliotek
JGA
JAVA 5+
Funktor bezargumentowy
UnaryFunctor
Funktor jednoargumentowy
BinaryFunctor
Funktor dwuargumentowy
Funktory te s zaprojektowane dla cisej wsppracy z Jav 5, gdy korzystaj z typw generycznych (ang. generics) (ktre zostay omwione w rozdziale 1.).
Klasa Generator jest w rzeczywistoci zdefiniowana jako Generator<R>. Posiada
ona bezargumentow metod gen, ktra zwraca obiekt typu R okrelony w konstruktorze klasy. Aby utworzy funktor bezargumentowy, moemy uy nastpujcego kodu:
122
Rozdzia 5
import net.sf.jga.fn.Generator;
public class CubeGenerator extends Generator<Double> {
double current = 0;
public Double gen() {
current = current + 1;
return current * current * current;
}
}
Na razie wyglda to tak, jakbymy dokadali sobie pracy bez wyranych korzyci. Jednake zalet takiego rozwizania jest moliwo tworzenia nowych metod,
ktre jako parametr przyjm dowolne funktory. Kolejny listing pokazuje, jak to
wyglda w praktyce:
public void removeMatches(List<Number> aList, UnaryFunctor<Number,Boolean>
functor) {
for (Number num : aList) {
if (functor.fn(num))
aList.remove(num);
}
}
Metoda ta usuwa wszystkie elementy z listy, dla ktrych funktor typu Number
->Boolean zwraca true (a dokadnie Boolean.TRUE; w Javie 5 typy te s rwnowane). Przeledmy teraz dwa sposoby napisania kodu usuwajcego liczby
parzyste z listy:
123
Metoda taka jak removeMatches moe by bardzo uyteczn czci biblioteki. Pozwala nam ona zastosowa kolejno kilka funktorw typu UnaryFunctor
<Number,Boolean> na danej licie:
removeMatches(numbers, lessThan30000);
removeMatches(numbers, greaterThan10000000);
Moemy osign ten sam efekt, uywajc klasy Iterables, ktra dobrze nadaje si do wykorzystania w ptlach for each wprowadzonych w Javie 5. Na
stronach JGA znajdziesz bardziej szczegowe przykady filtrowanych iteracji.
Oto krtki przykad ptli, ktra jest wykonywana wycznie na parzystych elementach danej listy:
UnaryFunctor<Number,Boolean> even = new EvenNumber();
List<Number> numbers = ...;
// dowolne wypenienie listy
for (Number aNumber : Iterables.filter(numbers, even)) {
System.out.println(aNumber);
}
124
Rozdzia 5
JGA
JAVA 5+
125
COLT
JGA
126
Rozdzia 5
-wyjcia. Po drugie, BitSet nie posiada metody do przeliczania podzbioru bitw na reprezentacj w postaci liczby cakowitej. Klasa BitVector z biblioteki
Colt jest bardziej wydajna i lepiej przystosowana do modelowania funkcji tego
typu. Zacznijmy od prostego przykadu demonstrujcego niektre z moliwoci tej klasy:
BitVector vec1000 = new BitVector(1000);
// rozmiar = 1000 bitw
// pocztkowo wszystkie bity s ustawiane na false (0)
vec1000.set(378);
// ustaw bit 378 na true (1)
System.out.println(vec1000.get(378));
// drukuje "true" na standardowym
wyjciu
vec1000.replaceFromToWith(1, 40, true);
// ustawia bity od 1 do 40 na true
// zwr bity z pozycji od 38 do 50 (wcznie)
BitVector portion = vec1000.partFromTo(38, 50);
//zwr warto typu long cigu bitw 3-10
long longValue = portion.getLongFromTo(3,10);
Moemy uy tych metod do symulacji bramek logicznych ukadw mikroelektronicznych stanowicych podstawowe cegieki tworzce komputer. Przykadem takich niskopoziomowych bramek s bramki AND, OR i NOT. Do oglnej
reprezentacji bramki logicznej moemy wykorzysta instancj klasy BitVector
jako wejcie i wyjcie funktora. Chocia Colt posiada wasne funktory oglnego
zastosowania, uyjemy tutaj API omwionego wczeniej, aby unikn nieporozumie. Funktor dla bramki AND mgby wyglda tak:
public class UnaryBitVectorAndFunction extends
UnaryFunctor<BitVector,BitVector> {
public BitVector fn(BitVector in) {
int oneBits = in.cardinality();
// ile bitw jest ustawionych na 1
int size = in.size();
// rozmiar wektora
BitVector outVec = new BitVector(1);
// jednobitowe wyjcie
outVec.put(0, size == oneBits);
// AND = same jedynki
return outVec;
}
}
127
S1
S0
Q0
Q1
Q2
Q3
Pierwsze trzy kolumny przedstawiaj stany na wejciu, pozostae na wyjciu. Selektory S0 i S1 decyduj, ktre wyjcie przedstawia stan wejcia, a pozostae wyjcia s wyzerowane. Stwrzmy teraz model tego ukadu. Kademu
sygnaowi trzeba przypisa indeks w obiekcie BitVector. W przypadku wej
przyjmijmy, e indeks 0 odpowiada wejciu D, 1 S0 i 2 S1. Poniszy
obiekt UnaryFunctor tworzy czterobitowy wektor zawierajcy wartoci sygnaw
wyjciowych:
public class QuadDemuxer extends UnaryFunctor<BitVector,BitVector> {
public BitVector fn(BitVector in) {
// czterobitowy wektor wyjcia, domylnie wyzerowany
BitVector outVec = new BitVector(4);
// pobierz warto wejcia D
boolean data = in.get(0);
if (data) {
// bity sterujce zwrcone jako zmienna int
int selector = (int) in.getLongFromTo(1,2);
outVec.set(selector);
}
return outVec;
}
}
COLT
128
Rozdzia 5
129
Moglibymy rwnie napisa wersje tych metod dla BitVector, uywajc kodu
z poprzedniej czci. Powysze funkcje wykorzystuj dostp do wewntrznych
danych (BitVector) klasy BitMatrix. (Napisaem to w ten sposb, poniewa BitMatrix nie posiada wygodnej metody dostpu do caych rzdw). Pamitaj, e
liczba bitw wejciowych powinna by utrzymana na niskim poziomie, poniewa
rozmiar tablicy prawdy ronie wykadniczo. Nie ma tu sprawdzania wartoci wejciowych i niewaciwe dane spowoduj wygenerowanie wyjtku. Bity wyjciowe,
ktre nie s uywane, s ignorowane wynika to ze sposobu, w jaki BitVector
konwertuje bity na wartoci long. Pamitaj te, e wartoci wyjciowe i wejciowe
s przetwarzane przy zaoeniu, e najmniej znaczcy bit jest bitem zerowym.
Wrcimy jeszcze do tablic prawdy, gdy utworzymy poczon sie blokw logicznych posiadajcych swoje wasne tablice prawdy.
JScience
130
Rozdzia 5
wielkoci, nie przejmujc si jednostkami, jakie za nimi stoj. W JScience podstawowe wielkoci fizyczne maj wasne klasy dziedziczce po wsplnej klasie
bazowej Quantity (Ilo). Oto przykady kilku z nich, razem z ich jednostkami
w ukadzie SI:
dugo (w metrach),
czas (w sekundach),
masa (w kilogramach),
temperatura (w kelwinach).
Klasy typu Quantity znajduj si w pakiecie javax.quantities. Klasy te zawieraj informacje o wielkociach, ktre mierzymy, i s duo bardziej precyzyjne
(czyli zapewniaj mniejsze prawdopodobiestwo bdw) ni zwyke wartoci
typu double do reprezentacji wartoci numerycznych. W dowolnej aplikacji mierzcej zwyke wielkoci, takie jak dugo, moesz uy jednej ze standardowych
klas JScience typu Quantity. Kada z tych klas przechowuje powizan z ni
jednostk wielkoci i dziki temu moe dokonywa automatycznych konwersji.
Jeli piszesz aplikacj zajmujc si komputerami, moesz napisa tak klas
do reprezentacji moliwych konfiguracji:
public class ComputerConfig {
double length, width, height;
double mass;
int ram, rom, network;
}
131
Teraz nasz program wie, e mamy tu trzy wielkoci okrelajce dugo, jedn
opisujc mas, dwie okrelajce pojemno pamici i jedn prdko przesyu
danych. Ma to jeszcze inn zalet: moemy podawa i otrzymywa wartoci wyraone w dowolnych jednostkach, wci majc je przechowane w jednostkach
ukadu SI. Zobaczmy, jak to wyglda w praktyce przypiszmy zmiennej wag
w funtach i pobierzmy j wyraon w kilogramach:
Measure<Mass> mass = Measure.valueOf(20, NonSI.POUND);
System.out.println(mass.to(SI.KILOGRAM));
Jak si pewnie domylasz, prba uycia jednostki niezgodnej z typem zmiennej spowoduje zgoszenie wyjtku. Wikszo jednostek ukadu metrycznego
znajdziesz w klasie SI, a pozostae w klasie NonSI. Jeli potrzebujesz jednostek,
ktre nie zostay dodane jeszcze do JScience, moesz zawsze stworzy wasne,
bazujc na tych ju istniejcych.
Jedna z bardziej tajemniczych jednostek angielskiego ukadu miar nazywa si
furlong i rwna jest jednej smej mili lub inaczej 220 jardom1. Jednostki tej
nie znajdziemy w JScience, ale moemy atwo j utworzy. Poniszy kod tworzy
tak jednostk, jak rwnie dodaje dla niej alias, aby moga by uyta w dowolnym miejscu w aplikacji:
Unit<Length> furlong = NonSI.MILE.times(0.125);
UnitFormat.getStandardInstance().alias(furlong, "furlong");
UnitFormat.getStandardInstance().label(furlong, "furlong");
Quantity fiveFurlong = Measure.valueOf("5 furlong");
Tworzenie aliasw dla nowych jednostek pozwala uywa ich pniej w opisach wielkoci fizycznych. Etykieta (ang. label) jest za stosowana przy wywietlaniu wartoci. Wielkoci i jednostki mog by mnoone i dzielone w celu otrzymania jednostek takich wielkoci fizycznych jak przyspieszenie (m*s2). W kolejnym
przykadzie wyprowadzimy now jednostk i uyjemy jej do wywietlenia prdkoci wiata (c):
Measure<Velocity> c = Measure.valueOf(299792458, SI.METER_PER_SECOND);2
//sowo "fortnight" oznacza dwa tygodnie (14 dni)
Unit<Duration> fortnight = NonSI.DAY.times(14);
UnitFormat.getStandardInstance().alias(fortnight, "fortnight");
UnitFormat.getStandardInstance().label(fortnight, "fortnight");
Unit<Velocity> furlongperfortnight = (Unit<Velocity>)
furlong.divide(fortnight);
System.out.println(c.to(furlongperfortnight));
1
132
Rozdzia 5
Nasza nowa jednostka jest jednostk prdkoci, gdy jest definiowana jako
dugo przez czas. Po uruchomieniu tego programu zobaczymy, e prdko
wiata w prni wynosi 1 802 617 499 785 253 furlongi na dwa tygodnie, czyli
troch mniej ni 2 terafurlongi na dwa tygodnie.
JScience
Dwa razy dwa rwna si 3,9999999998, jeli wierzy wynikom oblicze przeprowadzonych na zmiennych typu double. Wikszo programistw Javy miaa
okazj uywa typw double i float. By moe miae do czynienia rwnie z niektrymi metodami z klasy java.lang.Math. Klasa ta naley to najbardziej rdzennych bibliotek Javy i zawiera metody dla operacji na funkcjach, takich jak wykadnicze, logarytmiczne, trygonometryczne. Precyzja typu double wystarcza
dla wikszoci zastosowa, jednak dla naukowych aplikacji jej 11-bitowa cecha
i 52-bitowa mantysa (oparte na typie zmiennoprzecinkowym podwjnej precyzji
wedug IEEE 754) moe czasem spowodowa drobne bdy i szybko urosn
do duych problemw. Jest to szczeglnie istotne w obliczeniach iteracyjnych,
gdy rezultat poprzedniej iteracji jest dan wejciow kolejnej.
Aby rozwiza problem bdw zaokrglenia w zastosowaniach matematycznych, Java posiada dwie klasy dla operacji o dowolnej precyzji: BigDecimal
i BigInteger. BigInteger jest wietna do pracy z wyjtkowo duymi liczbami.
(Ale tak, zdaj sobie spraw, e nazwa dokadnie na to wskazuje!) Wielko tych
liczb jest ograniczona jedynie przez dostpn pami oraz prdko procesora.
Liczba taka jak 9700 jest zbyt dua, aby przechowywa j w zmiennej double lub
long, lecz nadaje si idealnie do zapamitania w zmiennej typu BigInteger. Podobnie BigDecimal moe precyzyjnie przechowa liczby takie jak 0,0123456
78987654321234567890123456, z ktr nie poradzi sobie liczba o mantysie
52-bitowej. Nastpujcy krtki przykad uywa klas BigInteger oraz BigDecimal
do reprezentacji tych liczb:
BigInteger nine = new BigInteger("9");
BigInteger nineToSevenHunredth = nine.pow(700);
BigDecimal exactNumber = new BigDecimal("0.
012345678987654321234567890123456");
BigDecimal moe reprezentowa precyzyjnie dowoln liczb, ktra ma sko-
czone rozwinicie dziesitne. Jest to spenione dla uamkw, ktre w mianowniku posiadaj wielokrotnoci liczb 2 i 5, np. 1/2, 15/4, 127/20, lecz nie jest dla
liczb takich jak 1/3 (0,333333) lub 5/7. Moe to powodowa kumulacj bdw
zaokrglenia w bardziej zoonych obliczeniach. W rzeczywistoci wszystkie metody klasy BigDecimal zwizane z dzieleniem wymagaj parametru skalujcego
133
Przy wykonywaniu oblicze arytmetycznych o dowolnie wysokiej precyzji najlepiej jest przechowywa licznik i mianownik w osobnych zmiennych. Poniewa
w podstawowych bibliotekach Javy nie ma obiektw dla uamkw zwykych o dowolnej precyzji, by moe pomylae o napisaniu wasnej klasy. Wielu ludzi
stworzyo klasy tego typu:
public class HugeFraction {
private BigInteger numerator, denominator;
// metody dla operacji na uamkach
public HugeFraction divide(HugeFraction other) {
// policz rezultat
return result;
}
}
W bibliotece JScience istnieje kilka klas sucych do przeprowadzania operacji o dowolnie wysokiej precyzji. Pierwsza z nich to LargeInteger, podobna do
BigInteger ze standardowej dystrybucji Javy. LargeInteger jest zoptymalizowana
ze wzgldu na prdko i wydajno w czasie rzeczywistym i implementuje interfejs Ring (struktura algebraiczna) uywany w teorii liczb i obliczeniach macierzowych. Posiada rwnie zwizany ze sob format XML. Klasa Rational3 bazuje
na niej w celu umoliwienia reprezentacji uamkw a/b o nieskoczonej precyzji,
dla a i b bdcych liczbami cakowitymi rnymi od zera. Klasa Rational jest niezmienna wszystkie jej metody zwracaj wynik, zamiast zmienia oryginalny
obiekt. Dziaa to dokadnie tak, jakby mg si spodziewa:
Rational
Rational
Rational
Rational
Rational
oneThird = Rational.valueOf("1/3");
nine87654321 = Rational.valueOf("987654321/1");
msixteen = Rational.valueOf("-16/1");
msixteenOver987654321 = msixteen.divide(nine87654321);
aNumber = oneThird.times (msixteenOver987654321);
134
Rozdzia 5
JScience
We wczeniejszych czciach tego rozdziau pokazalimy korzyci pynce z moliwoci manipulowania funkcjami, tak jakby byy one obiektami, przez przekazywanie ich jako parametrw do metod. W podrozdziale sprbujemy spojrze
na funkcje z matematycznego punktu widzenia. JScience, Colt, JGA (omawiane
wczeniej) wszystkie z nich zawieraj swoje wasne implementacje funktorw
i kada z nich ma swoje zalety. Wersja z JGA jest bardzo dobra w zastosowaniach
oglnego typu z powodu swojej prostoty i oglnoci. Colt zawiera wicej wbudowanych funktorw (patrz klasa Functions), lecz nie zapewnia oblicze o dowolnie wysokiej precyzji. W niniejszym podrozdziale omawiamy JScience, poniewa API to posiada oglny zrb dla operacji algebraicznych i wielomianowych
moliwy do zastosowania z dowolnymi obiektami implementujcymi interfejs
Ring (takimi jak Real bd Rational lub Twoimi wasnymi klasami bdcymi implementacj piercieni).
Obiekt typu Ring posiada metody mnoce i dodajce oraz operacj odwrotn dla kadej z tych metod. Klasa Polynomial (Wielomian) oznacza wyraenie
matematyczne zawierajce sum potg jednej lub wielu zmiennych przemnoonych przez wspczynniki (cytat z dokumentacji JScience). Moesz utworzy
wielomiany, ktre wsppracuj z dowoln klas typu Ring. Na nasze potrzeby
zdefiniujemy wielomian zmiennych rzeczywistych (Rational). Zacznijmy od staego
wielomianu. Klasa org.jscience.mathematics.functions.Constant jest podklas
Polynomial reprezentujc wielomian stopnia zerowego. Stwrzmy jeden egzemplarz za pomoc metody valueOf:
Constant<Rational> sixty = Constant.valueOf(Rational.valueOf("60/1"));
135
COLT
JGA
136
Rozdzia 5
137
W tej chwili mamy ju oglny szkielet dla czenia komponentw posiadajcych porty wejcia-wyjcia. Zaoyem tutaj, e komponent posiada jedn funkcj
wykonujc ca prac, pobierajc Object[] jako parametr i zwracajc rwnie Object[]. Jeli chcesz, moesz uczyni t funkcj na tyle elastyczn, e bdzie ona potrafia zwraca pojedynczy obiekt na pierwszy port wyjciowy i null
na pozostae. Na stronie internetowej ksiki znajdziesz implementacj klasy
Component wzbogacon o moliwo uycia typw generycznych Javy 5 (ang. generics). Zewntrzny proces kontroluje komponenty i zarzdza poczeniami midzy
nimi zaimplementujemy go pniej, korzystajc z API grafw. Jednake
wczeniej musimy zmieni nasz obiekt w jednostk przetwarzajc bity korzystajc z tablicy prawdy.
Moemy napisa jednoargumentowy funktor (podtyp UnaryFunctor), ktry
przetwarza tablic obiektw na bity, stosujc pewne proste reguy konwersji.
Funkcja powinna by na tyle elastyczna, eby interpretowa kady obiekt w tablicy jako bit w ten sam sposb (Boolean, niezero, nie-null). Zamy, e metoda
arrayToBits konwertuje tablic na bity. Przekonwertowane bity s interpretowane zgodnie z tablic prawdy i daj bity wyjciowe. Te z kolei s zwracane jako
tablica Boolean[], tak aby komponent mg przesa rezultat na swoje porty wyjciowe. Zamy, e metoda bitsToArray potrafi tego dokona. Poniszy przykad
jest uproszczon wersj faktycznej funkcji, ktra mogaby by uyta z nasz klas
Component:
138
Rozdzia 5
JGraphT
JAVA 5+
W rozdziale 4. odkrywalimy Sie semantyczn. Standard RDF, ktry omawialimy, modeluje te sieci jako etykietowane grafy skierowane. Grafy oznaczaj tu
sie wzw lub wierzchokw. W teorii grafw etykietowany graf skierowany
oznacza, e kada krawd midzy dwoma wierzchokami posiada opis i kierunek.
Grafy Jena i RDF uyte przez nas wczeniej s implementacj grafw oznaczonych do specyficznych zastosowa, inne aplikacje mog jednak potrzebowa
innych typw grafw do modelowania oraz wykonywania operacji na nich. W tym
celu moesz wykorzysta JGraphT, atw w uyciu bibliotek do pracy z grafami
rnego rodzaju. Koncentruje si ona na samym modelu grafu, jego pocze
oraz wykonywaniu operacji na nim a nie na wizualizacji i wywietlaniu go.
W rozdziale 6. omwimy inne API, ktrego gwnym celem jest wizualizacja
grafw. Pki co jednak bdziemy budowa po prostu modele grafw.
Wzy w JGraphT mog by dowolnymi obiektami Javy. Model grafu opisuje,
w jaki sposb obiekty poczone s ze sob. Uywajc tego modelu, moesz zajmowa si poczeniami midzy obiektami, niezalenie od samych obiektw. Jest
to bardzo podobne do zaoe modelu Model-View-Controller (MVC, model-widok-kontroler) uytego w Swingu oraz frameworkach sieciowych. Teoria grafw jest uyteczna w symulacji i analizie wielu skomplikowanych systemw, takich
jak sieci komputerowe, obwody cyfrowe, ruch na autostradzie czy przesy danych.
Tworzenie grafu w JGraphT jest proste. Na pocztku tworzysz instancj wymaganego typu grafu. Nastpnie wywoujesz metod addVertex, aby doda nowy
obiekt Javy jako wierzchoek. Kiedy obiekt jest ju czci grafu, moesz wywoa
139
140
Rozdzia 5
graph.addEdge(Organs.HEART, Systems.CIRCULATORY);
graph.addEdge(Organs.LUNG, Systems.RESPIRATORY);
graph.addEdge(Organs.BRAIN, Systems.NERVOUS);
graph.addEdge(Organs.SPINAL_CORD, Systems.NERVOUS);
graph.addEdge(Organs.STOMACH, Systems.DIGESTIVE);
graph.addEdge(Organs.LIVER, Systems.DIGESTIVE);
141
JGraphT
JAVA 5+
W czci powiconej czeniu wzw stworzylimy ogln jednostk obliczeniow z portami wejcia i wyjcia, a w czci powiconej grafom poznalimy
sposb na czenie dowolnych obiektw Javy w struktur grafw. W tej czci
poczymy wejcia i wyjcia komponentw, uywajc JGraphT. Tym sposobem
bdziemy mogli utrzymywa poczenia portw niezalenie od implementacji
komponentw. W rzeczywistoci nie dbamy tutaj w ogle o to, co komponenty
robi, lub nawet czy przetwarzaj one wartoci logiczne. Kady komponent ma
metod process, ktra pobiera dane z portw wejciowych, przetwarza je i zwraca
rezultaty na porty wyjciowe. Moemy wywoa metod process dla kadego
z komponentw i wysa wynik na porty wyjciowe. Jeli uylimy grafu skierowanego, moemy przesa dane z wyj na wejcia kolejnych stopni poprzez
iteracj po wszystkich krawdziach. Dla kadej krawdzi wywoujemy metod
getValue na wierzchoku rdowym (OutputPort) i ustawiamy warto wyjciow
na wierzchoku docelowym (InputPort) za pomoc metody setValue. Moemy
teraz napisa klas, ktra zarzdza wierzchokami uywajc API grafw.
public class MetaComponentSimple {
private ListenableDirectedGraph<Object, DefaultEdge> graph;
public MetaComponentSimple() {
graph = new ListenableDirectedGraph(DefaultEdge.class);
}
public void connect(OutputPort out, InputPort in) {
Component source = out.getParent();
Component target = in.getParent();
//dodaj nadrzdne komponenty do grafu
if (!graph.containsVertex(source)) {
graph.addVertex(source);
}
if (!graph.containsVertex(target)) {
graph.addVertex(target);
}
// dodaj porty do grafu
if (!graph.containsVertex(in)) {
graph.addVertex(in);
}
if (!graph.containsVertex(out)) {
graph.addVertex(out);
}
// dodaj krawd od komponentu-rda do portu wyjciowego
graph.addEdge(source, out);
// dodaj krawd od portu wyjciowego do wejciowego
graph.addEdge(out, in);
// dodaj krawd od portu wejciowego do komponentu-celu
graph.addEdge(in, target);
}
142
Rozdzia 5
143
InputPort b = or1.getInputPort(1);
Component or2 = createOrGateComponent(2);
InputPort c = or2.getInputPort(0);
InputPort d = or2.getInputPort(1);
manager.connect(or1.getOutputPort(0), and.getInputPort(0));
manager.connect(or2.getOutputPort(0), and.getInputPort(1));
// ustaw wartoci wejciowe
a.setValue(true);
b.setValue(false);
c.setValue(false);
d.setValue(false);
manager.process();
// potrzebujemy drugiego wywoania, gdy mamy komponent dwustopniowy
manager.process();
System.out.println(y);
// wynik: false
JOONE
144
Rozdzia 5
jest rozwizaniem prostszym. Gdy ju stworzysz w edytorze swoj sie i zakoczysz proces nauki, moesz zagniedzi t sie i silnik Joone w swojej aplikacji. Rysunek 5.3 pokazuje edytor graficzny w uyciu oraz jedn z przykadowych
sieci Joone.
org.joone.net.NeuralNetLoader;
org.joone.net.NeuralNet;
org.joone.engine.Monitor;
org.jonne.io.FileOutputSynapse;
145
JGAP
COLT
146
Istniej problemy, dla ktrych nieatwo jest znale waciwy algorytm do ich
rozwizania. Jest to szczeglnie problematyczne w wypadku procesw, ktre wymagaj czstych zmian algorytmu w celu uwzgldnienia zmiennych warunkw
rodowiska programu. W takich przypadkach moesz sprbowa napisa program, ktry samodzielnie wypracowuje rozwizanie. Jest to tak zwany algorytm
genetyczny (ang. Genetic Algorithm, GA). Ten typ programowania polega na
wyprbowaniu wielu rozwiza i wybraniu najlepszego. W kadym cyklu prb
najlepiej przystosowane elementy ze zbioru rozwiza (wedug wybranej funkcji
oceny ang. fitness function) s wybrane do rozmnoenia i tworz nastpne
Rozdzia 5
pokolenie. Nastpnie nowe pokolenie rozwiza jest poddawane mutacjom i krzyowane z innymi, co prowadzi do powstania wielu nowych wersji rnicych si
od poprzednich. Proces powtarza si dla kolejnych generacji.
Czasami proces ten prowadzi do powstania precyzyjnie wykalibrowanego algorytmu ju po kilku iteracjach. By moe nawet trudno bdzie zrozumie, jak
dokadnie dziaa wybrany algorytm i moe si on rni zdecydowanie od rozwizania, ktre wybralibymy, piszc je rcznie, poniewa funkcja oceny wybiera w tym wypadku algorytmy najskuteczniejsze, takie te bd algorytmy wytworzone przez ten proces.
Istnieje wiele bibliotek dla algorytmw genetycznych stworzonych w Javie.
Wiele odnonikw znajdziesz na stronie internetowej ksiki. W tej czci publikacji przyjrzymy si jednej z nich JGAP (ang. Java Genetic Algorithms
Package pakiet algorytmw genetycznych dla Javy). Zacznijmy od kilku podstawowych poj uywanych w dziedzinie algorytmw genetycznych. Terminy te
s zapoyczone z genetyki, mimo e obiekty uywane w tych algorytmach maj
raczej niewiele wsplnego z DNA. Chromosom (lub genom) przedstawia zbir
moliwych podej do rozwizania problemu, a gen przestawia jednostk w chromosomie (allele s konkretnymi odmianami genu, podobnie jak z zalenoci
klasa-instancja). Gen moe by acuchem tekstowym, liczb, drzewem, programem lub dowoln inn struktur. Aby uywa JGAP, musisz na pocztku wybra
genom, ktry odpowiednio reprezentuje przestrze twojego problemu. Nastpnie
wybierasz funkcj oceny dla testowania indywidualnych osobnikw populacji.
Na koniec tworzysz obiekt konfiguracji, aby opisa charakterystyk procesu, i moesz ju rozpocz proces rozmnaania osobnikw.
Uyjemy kodu z naszego przykadu tablicy prawdy z czci Bity duego
kalibru, gdzie stworzylimy demultiplekser 1-do-4. Stworzylimy wtedy tablic
prawdy dla demultipleksera z dwoma wejciami adresowymi, pojedynczym wejciem danych i czterema wyjciami danych. Wymaga to dokadnie 32 bitw
w tablicy prawdy. Moesz potraktowa to jako testowanie pojedynczego genu
o staej dugoci rwnej 32 bity w naszej symulacji genetycznej. Jak si okazuje,
nie dziaa to najlepiej w naszej aplikacji, poniewa przestrze poszukiwania jest
rwna caemu zakresowi wartoci typu int. Moemy zaprojektowa to lepiej,
uywajc genu czterobitowego reprezentujcego bity wyjciowe i chromosomu
o dugoci 8. Poniewa cztery bity wyjciowe dziaaj jako cao, okazuje si to
by duo lepszym wyborem dla genu. W wielu testach przeprowadzonych przy
100 000 pokole i populacji rwnej 200 gen 32-bitowy nie wytworzy pojedynczego dopasowania. Jednake z 4-bitowym genem zwycizca pojawia si szybciej
ni w dwudziestym pokoleniu.
Biblioteka JGAP posiada implementacj interfejsu Gene (gen) nazwan IntegerGene. Jest ona atwa do konwersji na typ Integer, wic bdzie si ona dobrze
integrowa z nasz tablic prawdy. Funkcja oceny w JGAP posiada metod evaluate
z parametrem typu IChromosome, ktra zwraca warto double. Wysza warto oznacza, e dany osobnik wykonuje zadanie lepiej. Tak wyglda nasza funkcja oceny:
147
148
Rozdzia 5
Kod ten tworzy chromosom o omiu genach, z ktrych kady moe mie wartoci od 0 do 15. Nastpnie wstawia ten chromosom do obiektu konfiguracji.
Dalej ustawia funkcj oceny i rozmiar populacji, tworzy pocztkow przypadkow populacj i uruchamia symulacj, a na koniec wybiera najlepiej dopasowany
chromosom. W tym przypadku znamy z gry wynik, ale jeli potrzebowaby
wartoci zwyciskich alleli, mgby wydoby je z chromosomu. Jeli chcesz uy
czego innego ni String, Integer czy bit w tworzonych przez siebie genach,
moesz stworzy wasn implementacj Gene.
Algorytmy genetyczne s, jak wida, kolejnym potnym narzdziem dla programistw Javy, szczeglnie do rozwizywania problemw, w ktrych rozwizania da si testowa i w rodowiskach dynamicznych, gdzie moe nie istnie jedno
niezmiennie najlepsze rozwizanie. Rozwizanie, ktre tworzy na drodze ewolucji sie neuronow za pomoc API Joone oraz JGAP znajdziesz na stronie
internetowej ksiki.
JADE
149
Dziki maszynie wirtualnej zdolnej do pracy na wielu platformach oraz potnemu modelowi bezpieczestwa Java jest idealnym rozwizaniem do tworzenia agentw. Wyobra sobie na przykad wiele niegraficznych apletw pracujcych w rozproszeniu nad rozwizanie problemu. Istnieje wiele API dla Javy do
tworzenia agentw, istnieje nawet konsorcjum nazywajce si Fundacja na rzecz
inteligentnych agentw fizycznych (ang. Foundation for Intelligent Physical Agents
FIPA), ktre stworzyo zbir standardw do tworzenia frameworkw agentowych. My uyjemy API nazwanego Jade, ktre jest jedn z najpopularniejszych
bibliotek zgodnych ze standardami FIPA. Istnieje kilka zupenie niepowizanych
projektw dla Javy nazywajcych si Jade, wic upewnij si przy pobieraniu
z internetu, e wybrae ten waciwy. (Moesz te skorzysta z odnonikw
na stronie internetowej ksiki.)
W podrozdziale wprowadzimy bibliotek Jade przez przykad zwizany z gied papierw wartociowych. Inteligentne agenty sprawdziyby si wietnie do
tzw. program trading, czyli automatycznego kupowania i sprzedawania papierw wartociowych w oparciu o zdarzenia, takie jak zmiana cen, poday, nowe
raporty informacyjne. Szczeglnie przydatny byby tutaj system wieloagentowy.
Sprbujmy zilustrowa t ide, piszc prostego agenta, ktry kupuje 100 akcji,
gdy wystpuje pewien specyficzny zbir zdarze. Uyjemy pseudokodu do wykonania poczenia z hipotetyczn usug sieciow, pominiemy te wszelkie zagadnienia zwizane z prywatnoci i bezpieczestwem. (Signij do dokumentacji Jade,
a znajdziesz tam przykady z bezpiecznymi agentami.) Tak wyglda najprostszy
moliwy agent:
public class WorthlessAgent extends jade.core.Agent {
protected void setup() {
}
}
Jade wywouje metod setup, gdy agent jest pierwszy raz adowany (podobne dziaanie ma metoda init w apletach i main w aplikacjach konsolowych). W tej
metodzie powiniene umieci kod inicjujcy agenta oraz okreli jego zachowania. Zachowania (ang. behaviours) definiuj to, co agent robi w czasie swojego
ycia. Moesz wyobrazi to sobie jako co podobnego do funktorw. W naszym
wypadku moglibymy chcie, aby agent okresowo sprawdza serwer kursw, aby
otrzyma ostatnie ceny danych akcji. Ten agent, sprawdzacz wartoci, mgby
wysya wiadomo do agenta kupca, gdy cena osiga zadany poziom. Istnieje
wiele podklas klasy Behaviour, ktrych moemy uy. Uruchomimy TickerBehaviour (zachowanie typu tykajcy zegar) do sprawdzania ostatnich cen akcji.
Ten typ jest zachowaniem periodycznym, powtarzany jest w staych odstpach
czasu (tykniciach zegara). Poniej mamy kod zachowania sprawdzajcego ceny
co 300 sekund:
150
Rozdzia 5
Dziaanie koczy si po wywoaniu metody stop po 1000 tykniciach zegara. Teraz podepniemy t klas do agenta.
public class QuoteAgent extends jade.core.Agent {
protected void Setup() {
addBehaviour(new CheckQuoteBehaviour(this));
}
}
151
152
Rozdzia 5
Jade posiada wiele innych cech uatwiajcych tworzenie rozproszonych systemw wieloagentowych. Agenty mog dziaa na serwerach J2EE, w apletach,
w maych urzdzeniach takich jak telefony komrkowe czy PDA. Jade posiada
nawet szkielet ontologiczny dla semantyki agentw, tak aby agenty mogy si komunikowa odnonie swoich zada i posiada wsplne ich rozumienie. Przykady
zawarte w dokumentacji Jade pokazuj niektre bardziej zaawansowane zastosowania. Technologie agentowe odegraj prawdopodobnie wielk rol w przyszym
rozwoju internetu semantycznego, a umiejtno pracy z ju istniejcymi strukturami na pewno pomoe programistom Javy przygotowa si do tego.
JWordNet
153
Definicja
Meronim
Holonim
Sowo okrelajce wiksz cao w stosunku do jej czci. Przykad: rower jest
holonimem koa.
Hipernim
Sowo okrelajce bardziej ogln klas czego. Przykad: pojazd jest hipernimem
roweru.
Hiponim
JWordNet jest interfejsem open-source dla WordNet, ktry moesz wykorzysta w swoich aplikacjach. To API jest bardzo uyteczne w aplikacjach przetwarzajcych tekst. Program moe na przykad przetwarza tekst i napotka sowo
wing (skrzydo/skrzydeko). Sowo to moe mie kilka znacze. Jeli wczeniejsza
cz tekstu zawieraa sowo feather (piro), moesz uy JWordNet do wyszukania holonimw sw feather i wing. Program moe znale, e obydwa sowa
oznaczaj cz ptaka i e ptak jest typem zwierzcia. W tym kontekcie moesz
odkry prawidowe znaczenie sowa wing i przej do dalszego przetwarzania
bazujc na tej wiedzy.
Poniej mamy przykad Hello world z uyciem JWordNet, w ktrym sprawdzamy sowo wing, aby znale jego holonimy dla kadego znaczenia sowa.
configureJWordNet();
// sprawd w dokumentacji, co obejmuje konfiguracja
DictionaryDatabase dictionary = new FileBackedDictionary();
IndexWord word = dictionary.lookupIndexWord(POS.NOUN, "wing");
System.out.println("Znaczenia 'wing':");
Synset[] senses = word.getSenses();
for (int i=0; i<senses.length; i++) {
Synset sense = senses[i];
System.out.println((i+1) + ". " + sense.getGloss());
Pointer[] holo = sense.getPointers(PointerType.PART_HOLONYM);
for (int j=0; j<holo.length; j++) {
Word synsetWord = sense.getWord(0);
// haso (lemma) zwizane jest ze sowem, gdy obiekt synset zawiera wiele sw
System.out.println("
-jest czci-> " + synsetWord.getLemma());
// wyjanienie (gloss) zwizany jest z obiektem synset
System.out.println(" = " + sense.getGloss());
}
}
154
Rozdzia 5
Uyem znaku wielokropka, aby skrci niektre dugie linie tekstu. JWordNet
obsuguje sowniki plikowe, pamiciowe i bazodanowe. Istnieje rwnie wersja
RDF dla WordNet ten temat opisywany by w rozdziale 4. JWordNet jest
potnym narzdziem przy poczeniu z technikami opisanymi w rozdziale 2.
(dopasowanie tekstu) oraz rozdziale 4. (analiza semantyczna). Odnonik do danych
RDF i inne informacje o WordNet i JWordNet znajdziesz na stronie internetowej ksiki.
155