wtorek, 17 czerwca 2014

Słownik argumentów

W pewnej pythonowej bibliotece była pewna funkcja, która akceptowała dowolnie nazwane argumenty, a potem zapisywała je jako atrybuty znacznika HTML.

Coś w tym rodzaju:

def  tag( t, **keys ):
    print( "<" + t, end='' )
    for k in keys:
        print( ' ' + k + '="' + str(keys[k]) + '"', end = '' )
    print( "/>" )

Z rozpędu próbowałem ostatnio wywołać ją w taki sposób:

   tag( "circle", cx=100, cy=20, fill-opacity=0.6 )

To oczywiście nie działa, bo - cytuję:

>>> tag( "circle", cx=100, cy=90, fill-opacity=0.9 )
  File "", line 1
SyntaxError: keyword can't be an expression

Trzeba to zrobić tak:

tag( "circle", cx=100, cy=90, **{"fill-opacity":0.9} )
Używamy tu pythonowego zapisu służącego do przekazywania nazwanych argumentów przez słownik.

Pojedyncza gwiazka służy do przekazywania argumentów przez listę. Przekazywanie dowolnej liczby argumentów za pomocą tablicy nie jest niczym nowym. W języku C można to robić używając makrodefinicji va_start, va_list i pokrewnych, ale nie jest to elastyczny mechanizm. W JavaScript jest już lepiej - mamy apply() i call() w duchu lispowym. Cała idea pojawia się zresztą wyraźnie w sławnej SICP , ale, co ciekawe w oryginalnym interpreterze Johna McCarthy'ego - nie pojawia się wcale, ten pierwszy interpreter Lispu oparty był na eval.

To, co mamy w Pythonie i Javascripcie jest bardziej elastyczne i estetyczne - lista (słownik) argumentów może być zbudowana niezależnie, jako obiekt pierwszej klasy. W C to niemożliwe - musi ona pochodzić z wywołania naszej funkcji. Ale przynajmniej można ją przekazać dalej - robi się to tak:

#include 
#include 

void somefun( const char *fmt, ... )
{
        va_list  ap;
        va_start( ap, fmt );
        vprintf( fmt, ap );
        va_end( ap );
}

piątek, 13 czerwca 2014

Minority game

Jednym z najprostszych możliwych do wyobrażenia modeli rynku giełdowego (albo aukcyjnego, albo walutowego) jest minority game, czyli gra mniejszościowa. Polega ona na tym, że gracze podejmują decyzje równocześnie, niezaleznie, na podstawie danych historycznych, a wygrywają ci, którzy byli w mniejszości.

Rzeczywiście - na przykład rynek forex w przybliżeniu działa właśnie w ten sposób. Gracze decydują, czy kupić, czy sprzedać, a wygrywają ci, których było mniej.

Okazuje się, że badacze potrafili dojść do ciekawych wniosków konstruując tego typu modele [1]

Spróbujmy stworzyć minimalny nietrywialny model takiej gry. Najprostszy z najprostszych modeli składa się z trzech graczy (dwóch to za mało - musi być liczba nieparzysta, jeden to też za mało - zawsze przegrywa sam ze sobą, więc model jest trywialny) podejmujących decyzje zero-jedynkowe. Przykładowa partia gry wygląda np. tak:

WierszDecyzjaWynikPunkty
A B C A B C
1. 1 1 0 0 0 0 1
2. 1 0 0 1 1 0 1
3. 0 1 1 0 2 0 1
4. 0 0 0 1 2 0 1
5. 1 1 1 0 2 0 1
6. 1 0 1 0 2 1 1

Wygrał gracz A, bo aż dwa razy potrafił być w mniejszości: w wierszu 2. i 3.

Jak może wyglądać najprostsza możliwa taktyka gracza ? Może wykonywać zawsze ten sam ruch, może zmieniać je cyklicznie, może powtarzać wartość, która wygrała, powtarzać wartość, która przegrała, wybierać wartość, która najczęściej wygrała/przegrała w pewnym odcinku czasu itp itd. Intuicja mówi nam, że im dłuższą historię gracz bierze pod uwagę, tym lepiej będzie mógł przewidzieć wyniki. Wydaje się też, że bardziej wyrafinowany algorytm decyzji będzie wygrywał z prostymi strategiami.

Skupmy się na najprostszych taktykach. Wykonałem eksperyment obliczeniowy z czterema strategiami:

  1. strategia stałej decyzji 0
  2. strategia stałej decyzji 1
  3. strategia powtórzenia pozycji, która ostatnio wygrała
  4. strategia powtórzenia pozycji, która ostatnio przegrała

Skrypt jest tu:

#! /usr/bin/env python3

def  Player( mode ):
    """  Player( mode ) zwraca funkcję gracza w trybie mode, gdzie
         mode = 0, 1, 2, 3
         Dla mode=0,1 gracz powtarza zawsze 0 lub 1, dla mode=2,3
         gracza powtarza lub neguje poprzedni wynik

         Funkcja gracza wywoływana jest z poprzednim (historycznym)
         wynikiem gry (jako 0 lub 1), ma zwrócić decyzję gracza, jako 0 lub 1.
    """     
    def  pfun0( prev ):
        return 0

    def  pfun1( prev ):
        return 1

    def  pfun2( prev ):
        return  prev

    def  pfun3( prev ):
        return  1 - prev

    return (pfun0, pfun1, pfun2, pfun3)[mode]

def  game( a, b, c, len ):
    """  Wykonanie gry o dlugości len
         a, b, c - gracze
    """
    prev = 0
    score = [0, 0, 0]

    for i in range(0, len):
        bid1 = a( prev )
        bid2 = b( prev )
        bid3 = c( prev )

        count = 0
        if bid1: count += 1
        if bid2: count += 1
        if bid3: count += 1

        # Co wygrywa - prev = głos mniejszości
        prev = 1 if count<2 else 0

        if (bid1 == prev):
            score[0] += 1

        if (bid2 == prev):
            score[1] += 1

        if (bid3 == prev):
            score[2] += 1

    return score

if __name__=="__main__":
    total = [0, 0, 0, 0]

    for i in 0,1,2,3:
        for j in 0,1,2,3:
            for k in 0,1,2,3:
                score = game( Player(i), Player(j), Player(k), 41 )
                print( i, score[0] )
                print( j, score[1] )
                print( k, score[2] )

                total[ i ] += score[0]
                total[ j ] += score[1]
                total[ k ] += score[2]


    print( total )            


Okazuje się, że jeżeli obliczymy średnią efektywaność tych strategii we wszystkich kombinacjach (to znaczy - zakładając, że pozostali gracze stosują jedną ze strategii 1,2,3,4 z równym prawdopodobieństwem), to najlepsza jest strategia 3 - powtórzenia pozycji, która ostatnio wygrała.

Wyniki (w umownych punktach):

  1. strategia stała 0 : 672
  2. strategia stała 1 : 312
  3. strategia powtórzenia wygranej : 852
  4. strategia powtórzenia przegranej :132

Dociekliwy czytelnik zapyta, dlaczego strategie 1 i 2 mają różne wyniki, skoro są symetryczne. Wynika to z niesymetryczności skryptu (startuję zawsze od 0 - linia 30, można zamienić na 1 i wtedy będzie odwrotnie).

Można drążyć ten temat dalej - obliczeniowo lub googlowo - szukać narzędzi teorii gier, które mają tu zastosowanie. Ale jedne wniosek może się nasunąć od razu - na rynku forex i na giełdzie mogą występować trendy (przynajmniej w krótkiej skali czasowej) - powtórzenie ruchu wygrywającego ma szanse powodzenia.

[1] Challet, Damien, Matteo Marsili, and Yi-Cheng Zhang. "Modeling market mechanism with minority game." Physica A: Statistical Mechanics and its Applications 276.1 (2000): 284-315.

środa, 7 maja 2014

Myślenie abstrakcyjne w Pythonie

Wpływ używanego języka na myślenie można nieraz odczuć samemu, jeśli w tym samym czasie programuje się dużo w różnych językach. Mając głowę wypełnioną pythonowymi narzędziami (comprehension, generatory, iteratory) próbowałem odruchowo zamienić wektor par w C++ (uzyskany z jakiejś funkcji) na odpowiednią mapę:
   std::vector< std::pair >  ->  std::map
W Pythonie analogiczna konstrukcja jest natychmiastowa:
   >>> x = [ (1,"a"), (2,"b") ]
   >>> dict( x )
   {1: 'a', 2: 'b'}
W C++ jednak analogia nie działa: Zamiast :
   std::vector< std::pair > v;
   std::map  m( v );
Musimy napisać :
   std::vector< std::pair > v;
   std::map  m( v.begin(), v.end() );
Ale to jest jeszcze nic. Trudnośc pojawiła się dopiero, gdy uświadomiłem sobie, że potrzebuję odwrotnej mapy (nie int -> string, a string -> int). W Pythonie mam od razu:
   >>> {name:value for value, name in x}
   {'a': 1, 'b': 2}

Próby użycia swap, transform itp. narzędzi w C++ zniechęciły mnie szybko, użyłem iteratorów i zrobiłem wszystko pętlami. Kod działa, ale nie jest ani prosty ani ładny, zamiast z jednej składa się z kilku linijek i zawiera dodatkowe obiekty, stworzone tylko po to, by to przekonwertować.

Z ciekawości uruchomiłem ghci i próbowałem analogiczną konstrukcję wykonać w Haskellu. Zaraz jednak okazało się, że nie znam go na tyle, by zrobić to od razu, potrzebuję importować jakieś moduły, szukać API w hoogle itd. itp. Python zwycięża wszystko równowagą pomiędzy prostotą a możliwościami ekspresji. Mamy tam comprehension, iteratory, generatory, yield i obiekty. Kilka narzędzi, które pozwalają budować złożone struktury listowe, mapy i inne zwierzęta z ZOO funkcyjnego, a wszystko w sposób miły i prosty. Mamy interaktywną konsolę, help do API i to już dośc, by szybko pisać złożony kod. Po prostu zapisywać myśl w postaci kodu.

piątek, 9 listopada 2012

Rozwiązywanie równań - aplet z grą

Wracam do tematu rozwiązywania prostych równań, o którym pisałem przy okazji zadania z cegłą. Poniżej przedstawiam prototyp pewnej gry matematycznej (właściwie to nie aplet, jak napisałem w tytule, a zwykły javascript). Pierwsze wrażenia są zachęcające - może ktoś to rozwinie, a może ja to zrobię, jeśli znajdę czas.

ROZWIĄŻ RÓWNANIE !

Zadaniem gracza jest rozwiązanie równania. Przycisk z symbolem ▶ losuje nowe równanie do rozwiązania. Kolejne przyciski służą do wykonywania operacji na równaniu (pamiętacie zadanie o cegle - dokładanie cegieł na obie szalki, itp). Należy doprowadzić do sytuacji, w której po jednej stronie równania zostanie pojedyncze "X", nie pomnożone przez żadną liczbę, a po drugiej liczbowa wartość (np. X = 4).

To prosta gra, pojedyncza partia odpowiada dokładnie rozwiązaniu równania. Gdyby rozwinąć ten temat (może ktoś to zrobi - jeśli znajdę kiedyś podobny program/aplet - postaram się zamieścić tutaj informację) - otrzymalibyśmy narzędzie dydaktyczne !

Osoby, które uczą matematyki, albo - jeszcze lepiej - udzielają korepetycji (korepetycje pozwalają z bliższej odległości obserwować zmagania niedoświadczonego umysłu z matematyczną materią) uznają ten pomysł na pewno za coś ciekawego.

Tego typu gry pozwalają w przyjemny sposób przyspieszyć moment, w którym osoba ucząca się przeżywa coś w rodzaju olśnienia (albo jak niektórzy mówią - coś jej w umyśle "przeskakuje") i nagle wie już, jak się to robi ! (W tym przypadku - jak się rozwiązuje równania z jedną niewiadomą. Rzeczywiście, zadanie to należy do prostych - łatwo je zautomatyzować.) Jest to coś takiego, jak odkrycie taktyki w prostej grze komputerowej - sposobu, który gwarantuje, że z każdego labiryntu znajdziemy wyjście w skończonej liczbie kroków.

Gra zawiera pewien haczyk: niektóre rozwiązania prowadzą do ułamkowych wartości, a przyciski pozwalają operować tylko na liczbach całkowitych. Mnożenie i dzielenie może doprowadzić do utraty precyzji - błędy zaokrągleń nakładają się, kumulują i w rezultacie możemy skończyć w sytuacji bez wyjścia. Trzeba zawsze starać się zachowywać całkowite współczynniki, zwykle jest to możliwe.

Gra zawiera też ciekawostkę: mnożenie i dzielenie operuje na liczbach pierwszych; w pierwszej wersji miałem tylko mnożenie i dzielenie przez liczby od 2 do 7, okazało się to jednak niewystarczające kiedy przeglądarka wylosowała równanie:

5X + 1 = - 6X

Chcąc więc pomnożyć (lub podzielić) równanie przez jakąś liczbę, której nie ma na przyciskach (np. 10) trzeba ją rozłożyć w pamięci na czynniki (tutaj 10 = 2 × 5) i pomnozyć (lub podzielić) po kolei przez te czynniki.

A oto dłuższy przykład:

4X - 4 = -2 - X | / 4
X - 1 = -0.5 - 0.25X | + 1
X = 0.5 - 0.25X | - X
0 = 0.5 - 1.25X | × 2
0 = 1 - 2.5X | - 1
-1 = - 2.5X | × 2
-2 = - 5X | / 5
-0.4 = - X | × (-1)
0.4 = X | ROZWIĄZANIE !

Gracz otrzymał poprawne rozwiązanie, jak się jednak nabiedził ! Wszystko dlatego, że niepotrzebnie na początku szybko podzielił wszystko przez 4, musiał potem pomnożyć ! Widać tu, że przykład ten powstał zanim odkryłem, że brakuje dzielenia przez 11 !

Właściwa taktyka jest taka: po pierwsze zgromadzić wszystkie X-y po lewej (stosując dodawanie i odejmowanie), potem wszystkie liczby bez X po prawej (takim samym sposobem), a na końcu podzielić wszystko przez czynnik przy X.

I jeszcze kilka pomysłów na rozwinięcie i udoskonalenie tego programiku:

  • Cofanie ruchu ("Undo")
  • Zapis (przy użyciu "local storage" HTML5)
  • Mierzenie czasu rozwiązywania
  • Możliwość wpisywania własnego równania
  • Podpowiedzi systemu
  • Grupowanie (zwijanie) ciągów operacji (np. dwie operacje +3 i +4 dają +7)
  • Równania ze współczynnikami symbolicznymi (np. aX + 2b = b - 1)
  • Układy równań
  • Operacje na ułamkach zwykłych (widziałem gdzieś w sieci bibliotekę implementującą wieżę numeryczną ze Scheme w JavaScripcie)
  • ... i pewnie wiele innych możliwości

Zagadki i ćwiczenia

  1. Co zrobi program, jeśli równanie nie ma rozwiązania (np. 2X + 1 = 2X) ?
  2. Albo gdy równanie ma nieskończenie wiele rozwiązań (np. 3X = 3X) ?
  3. Jak długo trzeba było klikać przycisk ▶, żeby uzyskać przykłady odpowiadające powyższym sytuacjom 😉 ?
  4. * Czy każde zadanie wylosowane przez program da się rozwiązać używając zestawu przycisków, który jest do dyspozycji ?

wtorek, 6 listopada 2012

Jeszcze raz o foreksie

Jeden z niedoszłych adeptów foreksu upierał się kiedyś przy poglądzie, że na wykresach kursów walutowych istnieją wyraźne trendy i że powinno dać się je wykorzystać. Pytany o źródło takiego przekonania, pokazywał wykresy i twierdził, że to po prostu widać. Kolega odpowiedział mu (znam osobiście obu), że to złudzenie, a dowodem tego miał być prosty eksperyment: wygenerowanie wykresu losowego przebiegu, który z prawdopodobieństwem 1/2 w każdej chwili czasu idzie w górę lub w dół - ruch Browna. Podobno bardzo często na takim wykresie człowiek dostrzega trendy i tendencje, a nawet formacje analizy technicznej.

Kolega był szybkim koderem, więc błyskawicznie napisał coś w tym rodzaju:

awk 'BEGIN {srand();x=1000;for (i=0;i<1000;i++) {if (rand()>rand())x++; else x--; print x;}}' > tmp.txt;echo "plot 'tmp.txt' with lines; pause 10"|gnuplot

Miał trochę szczęścia (lub pecha), bo wykres był akurat wyraźnie stromy, trend był widoczny jak na dłoni ! Kliknij poniżej klawisz "LOSUJ", a wylosujesz kolejną instancję danych.

W praktyce CZASEM trafi się przebieg losowy, który WYGLĄDA na losowy, zwykle wygląda na regularny. Wniosek z tego jest taki: nie patrz zbyt naiwnie na wykresy, stosuj matematykę. Jeśli wierzysz w to, że odkryłeś Świętego Graala, sprawdź to pięć razy. Słuchaj ostrzeżeń brokerów o wysokim stopniu ryzyka związanym z handlem na foreksie ! Istnieje wiele przesłanek skłaniających do wniosku, że dla małych graczy forex to czysty hazard. Więksi być może wiedzą więcej.

wtorek, 16 października 2012

Nowe auto

Ach, ile bym dał to,
By mieć nowe auto.
Jak wiele bym zniósł,
By mieć nowy wóz.

Dałbym złota górę,
By mieć nową furę.
Całą swą krwawicę
Poświęciłbym bryce.

Byłoby wspaniale !
Tak, to prawda, ale
Mam za mały dochód,
By kupić samochód.

niedziela, 7 października 2012

Przekręcanie słów

Człowiek jest w stanie bez trudu odczytać tekst, w którym wprowadzone zostały błędy - język ludzki jest nadmiarowy. Poniżej znajduje się przycisk, który miesza tekst widoczny na ekranie w sposób, który pozwala jednak go odczytać.

Sztuczka polega na tym, żeby za bardzo tego tekstu nie pomieszać. Dozwolona jest zamiana blisko położonych liter, przy czym pierwsza i ostatnia litera wyrazu powinny pozostać na swoich miejscach. Tak zakłócony kod mózg ludzki jest w stanie odszyfrować. Zobacz, co stanie się, jeśli dopuscimy większy stopień pomieszania liter.

czwartek, 4 października 2012

Wiedza w bazie danych

Czy może istnieć baza danych, zawierająca całą ludzką wiedzę, którą można przeszukiwać za pomocą języka zapytań podobnego do SQL ?

Coś takiego jest celem badaczy sztucznej inteligencji. Taką bazę danych nazywa się ontologią - i trzeba przyznać, że chociaż nie posiadamy jeszcze efektu końcowego - superinteligentnego robota, który odpowiada na wszystkie pytania, to jednak dotychczasowe wyniki badań są imponujące.

Przyjrzałem się ostatnio YAGO (Yet Another Great Ontology), jest to projekt nadający się do tego, by się z nim zapoznać, nawet, jeśli jest się amatorem w tych dziedzinach - posiada interfejs online-owy i względnie przystępny opis.

Sztuczna inteligencja z jednej strony powinna umieć porozumiewać się w języku naturalnym (to też ciekawa i dość już nawet zaawansowana dizedzina) ale przede wszystkim musi być wyposażona w wiedzę, którą określamy jako "common sense", czy "zdrowy rozsądek". Pewne podstawowe informacje są dla nas oczywiste, ale dla komputera nigdy - nawet najprostsze pojęcia i kategorie, którymi się posługujemy muszą być jakoś zaprogramowane.

Mamy Wikipedię - zawiera ona olbrzymie ilości danych, ale nie są ściśle skategoryzowane ani sparametryzowane. Zawiera jednak jakieś
kategorie (choć autorzy YAGO podają przykłady trudności: Elvis należy
do kategorii "Grammy Awards", choć nie jest NAGRODĄ a jej laureatem ...)
oraz INFOBOKSY - które są krokiem w kierunku uściślenia struktury danych.

Autorzy YAGO skorzystali z tych danych i z sieci semantycznej zawartej w WordNet (słownik języka angielskiego wyposażony w hierarchię powiązań semantycznych). Z połączenia tego powstała ontologia YAGO - można ją zapytać np. o polityków będących naukowcami, urodzonych w Hamburgu po roku 1900, albo o firmy założone w Berlinie przed 1970.

Nie jest to, jak się okazuje, jedyny tego typu projekt, jest ich już sporo, istnieje także bogata literatura na temat ontologii specjalistycznych.

YAGO i WordNet są dobrymi miejscami, gdzie można zajrzeć, nawet jeśli się nie zajmuje sztuczną inteligencją na co dzień, ale chce się
zapoznać z tym tematem, choćby pobieżnie.

środa, 3 października 2012

Rodzaje organizmów


W dzieciństwie dowiadujemy się, że żywe organizmy dzielą się na rośliny i zwierzęta i z niejakim zdziwieniem, ale też z radością przyjmujemy do wiadomości, że my (ludzie) też należymy do zwierząt.

Potem dowiadujemy się o bakteriach - dawniej uczono, że są one roślinami, ale dziś już wiemy, że nie. Nie są też jednak zwierzętami - cała sprawa jest skomplikowana, bo chcąc odpowiedzieć na pytanie, czy bakteria jest zwierzęciem, musimy sami zdefiniować, co rozumiemy, co chcemy rozumieć przez zwierzę.

A są jeszcze wirusy - coś, co nawet nie wiadomo, czy jest żywe, ale składa się z białek i kwasów nukleinowych i jakoś tam prawie żyje. O wirusach dowiadujemy się też dość wcześnie.

Stan obecnej wiedzy na temat klasyfikacji żywych organizmów jest mniej więcej następujący:

Wszystkie organizmy żywe na naszej planecie (a wielu naukowców sądzi, że na innych również) składają się z podstawowych elementów - komórek - które mają wiele cech wspólnych, ale są też bardzo zróżnicowane. Zbudowane są z białek, tłuszczy i czegoś tam jeszcze i potrafią się powielać (rozmnażać, kopiować) dzięki skomplikowanym reakcjom chamicznym z udziałem kwasów nukleinowych RNA i DNA.

Niektóre z tych organizmów składają się z jednej komórki, (jednokomórkowce) a niektóre z wielu (wielokomórkowce). Komórki te (w zależności od gatunku organizmu) mogą być proste, lub bardziej skomplikowane, mogą zawierać pewne podstruktury, będące same jakby mini-komórkami.

Istnieje wielka grupa organizmów (należą do niej rośliny, zwierzęta i my), których komórki zawierają jądro - dużą wydzieloną strukturę, w której zachodzą ważne reakcje i która steruje komórką. Są to eukarionty. Nie-eukarionty to prokarionty - są prostsze i o ile wiem, zawsze jednokomórkowe. To właśnie do nich należą bakterie.

Eukarionty podzielono początkowo na protisty, grzyby, rośliny i zwierzęta. Grzyby na poziomie komórkowym bardziej przypominają zwierzęta niż rośliny. Protisty to szeroka kategoria pierwotniaków, do której zaliczono wszystko, co nie jest grzybem, rośliną lub zwierzęciem. Podział ten był długo uznawany i dlatego jest popularny - dzisiaj oceniany jest raczej jako sztuczny.

Obowiązująca obecnie klasyfikacja eukariontów bazuje na dokładniejszej wiedzy o budowie ich komórek i opiera się na sześciu "supergrupach" (Opisthokonta, Amoebozoa, Excavata, Rhizaria, rośliny i Chromalveolata). Zwierzęta i grzyby (razem z paroma jeszcze innymi kladami przynależą do supergrupy Opisthokonta.

Oto (pochodzący z zasobów Wikimedia Commons) schemat podziału eukariontów:


rys: Agnieszka Kwiecień, licencja: CC-BY 3.0

Cegła i piórko, czyli co to jest równanie

Jesteś wykształcony ? A czy wiesz, co to są równania - i po co są równania, do czego służą ?

Chociaż każdy z grubsza wie, co to jest równanie, sporo ludzi nie ma wyrobionej intuicji dotyczącej ich użycia - układania i rozwiązywania.

Tymczasem pewne proste reguły matematyki może pojąć kaźdy, skoro uczy się ich dzieci w szkole ...

Równanie to sposób zapisu związku między wielkościami, o których mówimy - tak, by łatwo było nam o nich wnioskować. W życiu spotykamy się z licznymi problemami, które upraszczają się znacznie, jeśli zastosujemy równanie.

Na przykład:

  • Ile pracodawca płaci za godzinę brutto, jeśli za sto dziesięć godzin zapłacił do ręki 1290 zł, a stawka podatku wynosi 19 % ?

  • Ile farby potrzeba na kwadratowy pokój o powierzchni 8 metrów i wysokości 2.40, jeśli na metr ściany trzeba 7 l ?

  • Ile pali samochód na 100 km, jeśli jechał dwie godziny z prędkością 140,
    a zapłaciliśmy 26 zł za benzynę po 6.10 zł za litr ?
Czy czegoś to Wam nie przypomina ? No tak - zadania tekstowe ! Przychodzą na myśl słynne pociągi ze stacji A do stacji B, ale w dzisiejszych czasach założenie o stałej prędkości pociagu jest rażąco nierealistyczne ...

Znane są też następujące anegdotyczne zagadki:

  • Cegła waży kilo i pół cegły, ile ważą dwie cegły ?
  • Kapelusz z piórkiem kosztuje dwa dwadzieścia. Kapelusz jest droższy od piórka o dwa złote; ile kosztuje piórko ?
Rozwiązywanie takich zadań tekstowych składa się z dwóch etapów: z ułożenia równania i z jego rozwiązania. Omówię to na przykładzie owej cegły i piórka, ponieważ zadanie to łatwo zobrazować wizualnie. Po pierwsze : szukamy równania. Zadanie o cegle ukrywa przed niewprawnym czytelnikiem poszukiwane równanie, bo jest wypowiedziane zwięźle, nie zawiera sformułowań "równa się, jest równe", a pytanie jest włączone w treść. Aby je rozplątać, należy się skupić, wysilić, uspokoić (to najważniejsze) i wyobrazić sobie całą rzecz plastycznie:

Może - zamiast wypisywania równania, które tu zobrazowano, przejdziemy od razu do jego rozwiązania - na rysunku, bez zapisu algebraicznego. Mamy "sytuację szalkową", tzn. jakąś wagę, na której coś leży, a waga jest w równowadze. Będziemy się starali wyobrazić takie operacje, które doprowadzą nas do końca GRY . Bo to jest GRA - zdejmuj lub wkładaj coś na wagę w taki sposób, aby dojść do sytuacji, gdy na jednej szalce są dwie cegły (nie więcej i nie mniej), na drugiej pewna liczba odważników (ale żadnych cegieł), a waga jest w równowadze. Szukamy zatem przejścia z sytuacji początkowej do następującej sytuacji końcowej:

Nie wiemy ile odważników będzie po prawej stronie (to jest nasze pytanie - ile ważą dwie cegły, stąd wielokropek na prawej szali !), nie wiemy też ile będzie potrzeba kroków. Dozwolone operacje nie powinny wychylić wagi ze stanu równowagi.

NIE WOLNO więc:

  • (zasada 1) zdejmować ani kłaść niczego tylko po jednej stronie wagi
WOLNO zaś:
  • (zasada 2) po obu stronach wagi położyć lub zdjąć równoważne ciężary
  • (zasada 3) zamienić szale miejscami

Oto jak mogłyby wyglądać możliwe próby:
Na obie szalki dołożyliśmy po cegłówce, ale chyba nie wiemy, co dalej ... Może spróbujemy inaczej, dołożymy po półtorej cegłówki:
... i co dalej ? Nie bardzo wiemy ... W takim razie spróbujmy odejmować:
Ściągamy z obu szalek po połówce cegłówki:
A w tym miejscu zauważmy, że skoro obie strony są równoważne, możemy obie podwoić i wtedy równowaga zostanie zachowana !
I znowu !
I mamy nasze rozwiązanie.

Nasze wagi szalkowe, to równania. Odważniki to liczby, a cegły to niewiadome, na przykład X . Sytuacja wyjściowa odpowiada równaniu:

X = 1 + ½ X

A kroki naszego rozwiązania zapisuje się następująco:

X = 1 + ½ X

½ X = 1

X = 2

2 X = 4

A teraz kapelusz i piórko. To zadanie można rozwiązać przy pomocy układu dwóch równań. Zasada jest taka sama. Należy wyobrazić sobie dwie wagi i operacje na nich (co prawda mowa tu o cenie, nie o wadze, więc pewnie trzeba by wyobrażać sobie jakieś cenniki, albo faktury ...). Mamy dwie niewiadome, ale nic nam to nie szkodzi. Dotąd manewrujemy ciężarami, aż na lewej szalce zostanie to, o co chodzi (w tym wypadku P) a na prawej jakaś liczba bez niewiadomych.

K + P = 2.20     ( Kapelusz z piórkiem kosztuje 2.20 )

K = P + 2     ( Kapelusz jest droższy od piórka o 2 złote )

Wkładamy wszystko na jedną wagę (dodajemy równania stronami):

2 K + P = 4.20 + P

Ściągamy z obu szalek piórko:

2 K = 4.20

Dzielimy to na pół:

K = 2.10

Z tekstu zadania wnioskujemy, że: P = 0.10

środa, 4 listopada 2009

JavaScript jako język funkcyjny

JavaScript, język znany powszechnie jako wbudowana maszyna skryptowa przeglądarek webowych, jest kompletnie niedoceniany jako język programowania. Tymczasem jest to zgrabny i mały, ale bardzo elastyczny język dynamiczny. Obsługuje funkcje jako obiekty pierwszej klasy, domknięcia (closures) i funkcje anonimowe. To sprawia, że jest pełnoprawnym członkiem rodziny języków funkcyjnych, a ponieważ jego składnia jest prosta i zbliżona do C, posiada wielką siłę wyrazu, niektórzy zgodzą się nawet, że większą niż języki obiektowe oparte na klasach.

Sam język ani standardowa biblioteka nie posiada wielu udogodnień, ale moc wyrazu JavaScript (może należałoby pisać ECMAScript, ale w dalszym ciągu pozwolę sobie konsekwentnie używać tej pierwszej nazwy) jest tak duża, że potrzebne mechanizmy łatwo definiujemy.

Jako pierwszy przykład rozpatrzę iteratory. Chcemy stworzyć obiekt pozwalający na łatwe indeksowanie tablic, a w przyszłości będący wzorem dla ogólniejszych mechanizmów (wykorzystam go poniżek opisując implementację teoriomnogościowych zbiorów). Nasz iterator to funkcja, która po utworzeniu ustawia się na początku sekwencji, każde jej wywołanie generuje kolejny element, a gdy sekwencja się skończy, zwraca obiekt niezdefiniowany:

function iterator( arr ) {
        var index = 0;

        return function() {
                if ( index >= arr.length )
                        return undefined;
                return arr[ index++ ];
        }
}

Funkcja "iterator" jest konstruktorem iteratora, zamyka tablicę "arr" i zmienną "index" w domknięciu i tworzy funkcję używającą tych obiektów. Rezultatem wywołania funkcji "iterator" jest właśnie iterator. Jego pierwsze wywołanie zwraca pierwszy element tablicy, kolejne wywołania zwracają kolejne elementy. Na przykład:

var it = iterator( [1,2,3,4] );
for ( x=it(); x != undefined; x=it() )
{
     print( x );
}

Taki kod wypisze zawartość tablicy.

Tak skonstruowany iterator jest obiektem-funkcją. Widzimy, że definicja nasza była zwięzła i przejrzysta, dzięki domknięciom i funkcjom pierwszej klasy.

Biblioteki języków obiektowych zawierają definicje różnorakich kolekcji, list, kolejek, wektorów, map itp. Postanowiłem skonstruować na próbę zestaw funkcji i obiektów JavaScript odzwierciedlających podstawowy rachunek aksjomatycznej teorii mnogości. Użytkownicy Javy czy STL z pewnością nie będą pytać o celowość definiowania tak ogólnych mechanizmów.

Nasze zbiory mogą zawierać dowolne elementy (w końcu po to JavaScript jest językiem o słabej typizacji, żeby z tego faktu korzystać). Dla każdego z nich musi istnieć sposób (funkcja? metoda?) na określenie przynależności dowolnego obiektu. Poza tym chcemy mieć możliwość wykonywania takich podstawowych operacji jak dodawanie, selekcja podzbioru (wybór elementów spełniających podany predykat), tworzenie zbioru potęgowego. Siła programowania funkcyjnego polega na tym, że używając kilku prostych pojęć budujemy bardziej złożone, robiąc to prawie tak, jak definiuje się je w matematyce.

Załóżmy na początek, że zbiór jest reprezentowany przez funkcję przynależności. Wywołana z dowolnym argumentem powinna zwrócić wartość logiczną zdania "argument należy do tego zbioru". Używając tej konwencji definiujemy łatwo:

1) zbiór pusty:

   function  empty() {
    return false
   }

2) sumę zbiorów:

  function  sum( a, b ) {
    return  function( x ) {
     return a( x ) || b( x );
    }
   }

Tutaj już użyliśmy domknięcia, na razie sprawa jest prosta i piękna.

3) podzbiór elementów spełniających predykat P:

function  subset( a, P ) {
    return  function( x ) {
     return  a( x ) && P( x );
    }
   }

Tu widzimy, że reprezentacja zbioru jest tożsama z predykatem, a operacja "subset" z częścią wspólną.

Problem pojawia się w momencie, gdy próbujemy utworzyć zbiór potęgowy. Zbiór potęgowy danego zbioru X jest to zbiór wszystkich podzbiorów zbioru X. Zbiór jest podzbiorem innego, gdy zawiera się w nim. Zatem funkcja przynależności to zawieranie, a zatem:

4) zbiór potęgowy:

function  power( a ) {
    return function ( x ) {
     return includes( a, x );
    }
   }

Co jednak oznacza stwierdzenie, że zbiór a zawiera zbiór x ? Oznacza to, że ich część wspólna jest równa x !

5) zawieranie:

   function  includes( a, x ) {
    return  equals( subset( a, x ), x );
   }

A co oznacza równość zbiorów ? Aby zdefiniować ten predykat musimy albo posłużyć się zawieraniem, co spowoduje nieskończoną rekursję, albo wyliczyć wszystkie elementy. Rozszerzamy więc reprezentację zbiorów o funkcję zwracającą iterator. Pozwoli to wyliczyć wszystkie elementy i sprawdzić ich przynależność. Nasz zbiór jest więc dwójką składającą się z funkcji "contains" - będącej odpowiednikiem funkcji przynależności - i funkcji "iterator" zwracającej iterator ustawiony na pierwszy element zbioru, gwarantujący jednokrotne wyliczenie każdego elementu.

Teraz zbiór pusty wygląda tak:

1a) Zbiór pusty:

var empty = {
 contains:function() {return false},
 iterator:function() {return function(){return undefined}}
}

2a) Suma jest nieco bardziej skomplikowana:

function sum(a, b) {
 return {
  contains:function( x ) {return a.contains(x) || b.contains(x)},
  iterator:function()    {
   var i1 = a.iterator();
   var i2 = b.iterator();
   return function() {
    var x = i1();
    if ( x == undefined ) {
     while (true) {
      var next = i2();
      if ( next == undefined ) return undefined;
      if ( a.contains(next) ) continue;
      return next;
     }
    }
    else {
     return x;
    }
   }
  }
 }
}

Komplikacja bierze się z konieczności zagwarantowania braku powtórzeń w iteratorze. Iterator sumy domyka dwa iteratory składników, wyczerpuje pierwszy, a potem używa drugiego sprawdzając, czy zwrócony element nie był już wyliczony wcześniej.

3a) podzbiór elementów spełniających predykat P:

function subset( a, p )
{
 return {
  contains:function ( x ) {
     return a.contains( x ) && p( x );
    },
  iterator:function () {
     var it = a.iterator();
     return function() {
      var x;
      while ( true ) {
       x = it();
       if ( x == undefined ) return undefined;
       if ( p( x ) ) return x;
      }
     }
    }
 };
}

I wreszcie sprawca zamieszania, zbiór potęgowy:

4a) Zbiór potęgowy:

function power( a ) {
 return {
  contains:function( x ) {
     return includes( x, a );
    },
  iterator:function() {
     var div = divide( a );
     if ( div.head == undefined )
      return singleton( empty ).iterator();
     var tail_pow = power( div.tail );
     var tail_pow_iterator1 = tail_pow.iterator();
     var tail_pow_iterator2 = tail_pow.iterator();
     return function() {
      var x;
      x = tail_pow_iterator1();
      if ( x != undefined )
       return x;
      x = tail_pow_iterator2();
      if ( x == undefined )
       return undefined;
      return sum( singleton( div.head ), x );
     }
         }
 }
}

Pełne źródła tych procedur można pobrać tu: sets.txt, tam też znajdują się pomocnicze procedury "includes" i "divide". Ta druga posłużyła do wydzielenia jednego elementu i reszty - z dowolnego zbioru. Dzięki temu zbiór potęgowy mógł zostać zdefiniowany rekursywnie.

A teraz proszę popatrzeć, jak to ładnie działa:

Oto wynik działania programu testowego:
Zbior 4 - elementowy:
{1, 2, 3, 4}
Jego zbiór potęgowy:
{{}, {4}, {3}, {3, 4}, {2}, {2, 4}, {2, 3}, {2, 3, 4}, {1}, {1, 4}, {1, 3}, {1, 3, 4}, {1, 2}, {1, 2, 4}, {1, 2, 3}, {1, 2, 3, 4}}
Zbiór podzbiorów właściwych:
{{4}, {3}, {3, 4}, {2}, {2, 4}, {2, 3}, {2, 3, 4}, {1}, {1, 4}, {1, 3}, {1, 3, 4}, {1, 2}, {1, 2, 4}, {1, 2, 3}}
Albo:
{{4}, {3}, {3, 4}, {2}, {2, 4}, {2, 3}, {2, 3, 4}, {1}, {1, 4}, {1, 3}, {1, 3, 4}, {1, 2}, {1, 2, 4}, {1, 2, 3}}
Czy zbiór jest jednoelementowy ?
{} :  false
{1} :  true
{1, {}} :  false
Istnienie elementu o podanej wlasnosci:
{1, 2, 3, 4} , 3:  true
{1, 2, 3, 4} , 100:  false
Kwantyfikator ogólny:
Czy zbior jest dwuelementowy ?
{} :  false
{1} :  false
{{}, {1}} :  true
{1, 2, 3, 4} :  false

Warto zwrócić uwagę na sposób definiowania kwantyfikatorów - funkcje anonimowe (w notacji lambdapodobnej) dają możliwość nazywania zmiennych związanych pod kwantyfikatorem, więc da się tego używać bez wielkiego wysiłku. Porównawszy to z kodem, który trzebaby napisać w C++ używając <functional> widzimy moc wyrazu JavaScript.

I kto dalej twierdzi, że JavaScript to język do robienia animowanych buttonów w internecie ? No kto ?

poniedziałek, 7 września 2009

szablony w C++

Mechanizm szablonów w C++ umożliwia deklarowanie klas i funkcji sparametryzowanych typami lub wartościami. Klasa w C++ wprowadza przestrzeń nazw, w której można deklarować obiekty statyczne - daje to możliwość używania szablonów do deklarowania innych obiektów języka, nie tylko klas i funkcji - bezpośrednio nie byłoby to możliwe. Nie można na przykład zdefiniować szablonu tablicy, o tak:
template <class T>
T table[100];
Ale można uzyskać pożądany efekt w taki prosty sposób:
template <class T>
class t {
        public:
        static T table[100];
};

template <class T>
T t<T>::table[ 100 ];
Podobnie można postąpić z innymi kontrukcjami: Np. wyliczenie:
template <int N>
class t {
        public:
                enum en {
                        START=N,
                        STOP
                };
};
Szablonów można użyć do wielu nieoczywistych sztuczek. Oto jak można sprawdzić, czy dwa wyrażenia są tego samego typu:
template <class T>
bool same_type(const T&, const T&) {
        return true;
}

template <class T1, class T2>
bool same_type(const T1&, const T2&) {
        return false;
}

int main()
{
        std::cout << same_type(1, 2) << '\n';
        std::cout << same_type(1, 2.1) << '\n';
}
Kompilator oczywiście całkowicie optymalizuje taką funkcję - zamienia ją na stałą.

piątek, 24 lipca 2009

Unifikacja termów w C++

Jeden z moich znajomych napisał ostatnio zestaw klas w języku C++, która dzięki zastosowaniu operatora () do konstrukcji termów i operatora == do unifikacji pozwala programować w stylu Prologu w języku C++. Do obejrzenia tu: http://symbolism.110mb.com

Ci, którzy programują w Prologu, wiedzą, co to jest term. Term, to wyrażenie składające się ze stałych, zmiennych i wyrażeń typu f(x1, x2, ... ) gdzie f jest nazwą funktora (symbolem) a x1, x2, ... też są termami. Jeśli oznaczymy zmienne nazwami zaczynającymi się od dużych liter (X, Y, Z itp) a stałe innymi nazwami , liczbami itp, term może wyglądać tak:

f
ala( f, f(X, Y, 10), X)
ala( 0 )
i tak dalej. W skrócie mówiąc - unifikacja termów, to takie dopasowanie wartości zmiennych (wartości zmiennych też mają być termami) aby dwa unifikowane termy uzyskały tę samą wartość. Unifikacja może się nie udać, zmienne nie są wtedy zmieniane (mówi się też - ukonkretnione) Jeśli oznaczymy symbolem == operację unifikacji, możemy napisać:
f( X, 1 ) == f( 2, Y )                   
-> zmienna X zyskuje wartość 2, Y wartość 1

f( X, g( Y, 0 ), Y ) == f( 1, Z, g( 2 )) 
-> zmienna X zyskuje wartość 1, Y wartość g(2) a Z wartość g(g(2), 0)

f( X, g( 1 )) == f( 0, 2 )   -> unifikacja zawodzi, zmienne pozostają wolne.

sobota, 6 czerwca 2009

Spread, lewar i pipsy na rynku Forex

Wszyscy co prawda wiedzą, co oznaczają pipsy, lewar i tym podobne pojęcia, ale może nie wszyscy potrafią wyciągać odpowiednie wnioski z tej wiedzy. Tymczasem na wyniki strategii stosowanej na rynku forex wpływa równocześnie wiele czynników: rozmiar pozycji (pipsy), stosowany lewar, skuteczność (prawdopodobieństwo) i oczywiście spread (koszty stałe transakcji).

Ponieważ jest to wpływ równoczesny, sytuacja jest złożona, mimo, że w istocie chodzi tu o matematykę na szkolnym poziomie.

Musisz koniecznie wiedzieć, co dokładnie dzieje się gdy wykonujesz traksakcję o danych parametrach. Wyobraź sobie, że dysponujesz kwotą 100 $, wchodzisz na rynek z lewarem 10, przy spreadzie 4 pipsy (umawiamy się dla celów tych rozważań, że 10 pipsów = 1 promil) ustawiasz poziom 'take profit' na wysokości 30 pipsów i po kilku godzinach zgarniasz kasę. Pytanie - ile ? Jeśli to rozumiesz i umiesz wyliczyć, to dobrze, ale spójrz niżej, zobacz, czy czegoś nie pomijasz.

Przy lewarze 10 handlujesz w rzeczywistości 1000 $, przy spreadzie 0.0004 i TP=0.003 zarabiasz 0.0026 * 1000 = 2.60 $, co daje czynnik 0.026 profitu. W razie straty przy SL=-0.003 tracisz 0.0034 * 1000 = 3.40 $ ponieważ spread działa zawsze na niekorzyść gracza. Dlatego zysk i strata nie są symetryczne, mimo, że ustawiliśmy poziomy TP i SL w równych odległościach.

Wyobraźmy sobie hipotetyczną metodologię, która dla danej pary umożliwia prognozowanie ruchy kursu o 50 pipsów. Jej skuteczność niech wynosi 70 %. Oto jak wygląda wartość porfela gracza, który wykonuje 20 transakcji stosując opartą o taką prognozę strategię przy spreadzie 4 pipsy, trafiając "take profit" 14 razy: W zależności od zastosowanego lewara gracz zarabia aż do 170 %, ale widać jasno, że LEWARA NIE MOŻNA BEZKARNIE ZWIĘKSZAĆ w nieskończoność: w pewnym momencie następuje nasycenie profitu ! Dla lewara 120 obserwujemy już stratę. Lewar wpływa bardziej na wahania, a mniej na wynik końcowy.

Odpowiedzialność za taki fatalny stan rzeczy ponosi spread (czyli broker, który zgarnia całą kasę zachłannego gracza, podobnie jak krupier w kasynie). Oto jak wygląda zależność zarobku w naszej hipotetycznej sytuacji od zastosowanego lewara przy różnych spreadach: Słabsze strategie są jeszcze bardziej podatne na te efekty i wręcz nie działają na dużych spreadach, mimo, że nie stosujemy lewara.

Co jeszcze warto wiedzieć ?

Występujące w przyrodzie spready nieprzypadkowo mają taką wielkość, że działające strategie musiałyby mieć dzielność rzędu 65% lub większą - dla wielkości pozycji przekraczającej około dziesięciokrotnie wartość spreadu. To jest maksymalny poziom trafności, jaki można osiągnąć stosując znane metody (włączając w to sieci neuronowe, algorytmy genetyczne, filtry bayesowskie i inne metody - określane jako standardowe, choć nie są one proste).

Istnieje jeszcze jedna pułapka na chciwych graczy: "margin call". O tym też trzeba pamiętać. Można po prostu stracić wszystko za jednym zamachem, jeśli przedobrzymy z lewarem.

Tak więc rację ma Oanda, twierdząc, że dla tradera to właśnie niskie spready są istotne, a nie duże lewary. W warunkach bojowych lewar większy od 10 to lichwiarska pułapka ! Na stronach Oandy dokładnie opisane są te sprawy, ten broker stara się uczciwie informować o podstawowych regułach gry.

czwartek, 28 maja 2009

Paradoks skuteczności lekarstw

W jednym ze starych numerów Delty opisany był następujący paradoks:

Zbadano skuteczność dwóch lekarstw A i B. Okazało się, że wśród kobiet wyższą skuteczność miało A, natomiast w całej populacji wygrywało B. Nie byłoby to dziwne, gdyby nie fakt, że wśród mężczyzn również lepszym było lekarstwo A. Jak to możliwe ? Otóż badanie przeprowadzono w następujący sposób - zgłaszającemu się pacjentowi aplikowano losowo A lub B, po czym notowano wynik terapii.

Wyniki badania były następujące:

Badano 32 mężczyzn, 25 mężczyznom podano lek A, z czego 10 wyleczono. 7 mężczyzn leczono lekiem B, z czego 2 wyleczono. Skuteczność leków wynosiła więc wśród mężczyzn 40% dla A i 29% dla B.

Zbadano 25 kobiet, na 11 leczonych lekiem A wyleczono 9, pozostałe 14 leczono podając lek B, wyleczono 11. Skuteczność leku dla kobiet wyniosła więc 82% dla A i 79% dla B. Widać, że kobiety łatwiej się leczyło, ale wśród pacjentów obu płci lepszy był lek A.

Tymczasem po zsumowaniu liczb widzimy, że skuteczność A w całej grupie wynosi 53%, a B 62% ! Co ma więc zrobić lekarz, do którego przychodzi pacjent ? Zbadać jego płeć i przepisać A niezależnie od wyniku tego badania, czy nie badać i przepisać B ?

Istnieje wiele układów liczb tworzących taką sytuację. Podobne zadanie (tylko z innymi "didaskaliami") pojawiło się w konkursie Eulera, o którym już wcześniej tu pisałem.

Gdzie czytać o najnowszych osiągnięciach nauki

Gdzieś w początkach swojej przygody z internetem zetknąłem się z programem surfraw, a w przykładowych skryptach z adresem xxx.lanl.gov. Myślałem, że xxx wskazuje na pornografię, ale okazało się, że nie - krzywdziłem autorów. Jest to stary (ale do dziś działający) adres arXiv - wielkiego archiwum preprintów naukowych będącego kopalnią wiedzy o współczesnych naukach ścisłych. Archiwum to jest miejscem gdzie naukowcy z takich dziedzin jak matematyka, fizyka, informatyka, astronomia publikują swoje prace zanim zostaną one wydrukowane na papierze. Niedawno natknąłem się na "The physics arXive blog", którego autor codziennie omawia w sposób dostępny dla zainteresowanych laików jeden wybrany temat z archiwum. Oto zagadnienia, które podejmował ostatnio:

"Pierwszy dowód splątania w fotosyntezie"
"Jak używać pulsarów w nawigacji międzygwiezndej"
"Termodynamiczny limit rozmiaru mózgu"
"Odsłonienie sekretów ludzkiego chodu"
"Gdzie załamuje się zasada równoważności"
...

Wszystkie tematy ciekawie opisane, z kolorowymi ilustracjami i z aktualnymi odnośnikami do oryginalnych prac z arXiv.

wtorek, 17 marca 2009

Nowy freshmeat

"Świeże mięsko" jeszcze bardziej się odświeżyło - mamy nowy freshmeat 3.0. Nestety niedokończony ... W starej postaci używałem takich funkcji jak wyszukiwanie wg kategorii - teraz nie mam hierarchii kategorii, mam za to modną w Web 2.0 chmurę tagów ... czy to jest lepsze ? Na pewno nie, czekam na resztę.

Miałem też możliwość podglądania statystyk projektu - liczbę odwiedzin, ściągnięć, współczynnik żywotności, to wszystko co pozwala szybko ocenić i wstępnie zakwalifikować nieznany program. Mogłem też sortować wyniki wyszukiwania wg tych czynników - często to robiłem. Zamiast tego jest jakiś mikroskopijny wykres, nie wiadomo czego - stworzony przy użyciu google charts API, skądinąd przyjemnego. Ale statystyki mają wkrótce być - ponoć ulepszone.

Co gorsza, po zalogowaniu się nie potrafię znaleźć statystyk moich projektów - czy one gdzieś są ? W FAQ znalazłem sugestię, że "trzeba było testować wersję beta" - wszyscy testowali i nikt nie zgłaszał takich to a takich potrzeb. Hmmm ... Owszem, dostałem jakieś zaproszenie, ale nie chciało mi się. Mam jednak nadzieję, że używane przeze mnie funkcje będą tu nadal.

Poza tym nie ma nigdzie możliwości sciągnięcia całości bazy danych w formie XML - a była ! Podobno (tak piszą) jest możliwość pobrania rekordu projektu w JSon'ie - ale jak to zrobić ? Tego nie napisali.

Z ostatniej chwili - pojawiło się wiele komentarzy - ludzie pytają o wiele spraw, w tym np o XML - poczekajmy, co się z tym dalej będzie działo ... Jak ktoś tam napisał: "koniec końców - nie jest tak źle" ...

piątek, 6 marca 2009

Obrazek "inline" w HTML

Warto czasem pamiętać o różnych dziwnych sztuczkach. Na przykład o wstawianiu grafiki bezpośrednio w tekście HTML. Poniższy obrazek jest tu bezpośrednio wklejony w żródle HTML:

Aby to zrobić, trzeba użyć schematu "data" zdefiniowanego w RFC 2397. Ponieważ schemat ten obsługuje kodowanie base64, można wstawić dowolną grafikę.

Można także wstawić zagnieżdżoną stronę HTML, tym razem już bez kodowania base64, ale Internet Explorer odmówi renderowania elementu "data" z "nawigowalną treścią" - chodzi o względy bezpieczeństwa - filtry zabezpieczające różnorakie aplikacje internetowe przed atakiem typu cross-side scripting prawdopodobnie nie rozpoznałyby javascriptu zagnieżdżonego w elemencie zakodowanym w "data". A jak spreparować taki obrazek ? Po prostu użyć polecenia "base64" dostępnego w uniksie, a także w bibliotekach różnych języków ...

Używając tego mechanizmu Jeff Epler zaimplementował w JavaScript funkcje służące do generowania obrazków w locie po stronie klienta.

wtorek, 17 lutego 2009

Durczok, Lis, Kaczyński, Niesiołowski i nasze emocje

Pan Kamil Durczok stał się dla nas źródłem wesołości, pozwalając się sfilmować przy pracy. Nie przebił moim zdaniem Tomasza Lisa, który uraczył nas jakiś czas temu jeszcze dłuższym potokiem błota wylewanego na współpracowników. Nie dziwi mnie to ani nie gorszy, wolę co prawda ludzi kulturalnych, ale pogodziłem się z tym, że takich jest mało na świeczniku. Ale przecież pan Kamil uważa się za kogoś wyrastającego ponad poziom przeciętny, nie chciał stawać w szranki o nagrodę medialną razem z Kasią Cichopek - kimże ona jest przy nim ! Bez urazy ...

Wczoraj mogliśmy obejrzeć Tomasza Lisa w rozmowie na temat pana Czumy, a potem na innym kanale telewizyjnym pana Pospieszalskiego w dyskusji o eutanazji. I tu i tam widziałem gotujące się emocje (pogardę i wściekłość u Niesiołowskiego, gniew u Kaczyńskiego, pogardę i wściekłość u pana profesora bioetyka, którego nazwiska nie zapamiętałem - przepraszam). W ogóle wszędzie pełno obrażania, dokuczliwych złośliwości i jadu. Lis stale wyciąga jakieś stare nagrania z Kaczyńskim, aby ludziom pokazać, jak agresywne są Kaczory. Nie udała mu się jednak prowokacja, kiedy gościł Kaczyńskiego u siebie - chociaż zaprezentował mu filmik z Marcinkiewiczem, nie usłyszał nic poza zapewnieniami o dobrej woli. Prezes Kaczyński zmienił front i hamuje agresję, choć pewnie mu ciężko. Za to tydzień później, Lis razem z nowym gościem wspólnie szydzili z nieobecnego prezesa bez umiaru. Uśmiechali się pogardliwie pod nosem wymieniając porozumiewawcze spojrzenia wspominając jego wpadki i litując nad jego poziomem.

U Pospieszalskiego goście byli spokojni i opanowani, oprócz pana Profesora, którego nazwiska nie pamiętam - wojującego ateisty, który bardzo się sam zdenerwował z tego powodu, że połowa ludzkości wierzy w duszę. Odniosłem wrażenie, że złościł się po prostu dlatego, że nie okazano mu należnego respektu - pani redaktor, z którą rozmawiał, ośmieliła się go krytykować. Upomniał ją, że winna mu szacunek, jako, że jest PROFESOREM. Pani redaktor też była mocno zdenerwowana.

Wszystko to nastraja mnie dość smutno - światem nie rządzi wcale rozum, wbrew temu, co się nam wmawia. Rządzą nimi EMOCJE wywoływane przez media - czytaj - MANIPULACJA. Na szczęście chyba nie zawsze skuteczna - drugie na szczęście - zdecentralizowana ... Kto wywoła odpowiednie emocje w odpowiednim kontekscie, przeciąga wyborcę (czytelnika? konsumenta?) na swoją stronę. Ludzie tacy jak Lis próbują to robić zawodowo, politycy - też, ale mam nadzieję, że przynajmniej ci, którym wierzę, robią to dla słusznych celów.

poniedziałek, 16 lutego 2009

Skrzynka z narzędziami

Podczas pracy z plikami tekstowymi często powstaje potrzeba przeprowadzenia prostej operacji w rodzaju sortowania, zmiany kolejności, sumowania itp. Zwykle odruchem jest pisanie jednolinijkowca w AWK-u albo innym ulubionym języku. Niesłusznie. Czasem lepiej jest otworzyć skrzynkę z narzędziami i poszukać gotowca. W Unix-ie mamy mnóstwo małych gotowych programów. Zdarzyło mi się napisać program, który robił to, co shuf i inny, który wykonywał operację paste. Niepotrzebnie. Poniżej wymieniam kilka z tych narzędzi.

csplit:podział pliku na podstawie zawartości
cut:wybranie kolumn
join:połączenie plików wg wspólnej kolumny
paste:sklejenie plików kolumnami
shuf:mieszanie kolejności linii w pliku
split:podział pliku na równe kawałki
tac:wypisanie pliku liniami od tyłu
tr:zamiana znaków
uniq:wybranie linii powtarzających się

Warto zapoznać się z nimi - mają bogaty repertuar różnych opcji - na przykład program split może zliczać linie, albo znaki. Program paste może skleić pliki pionowo lub poziomo. Program shuf może mieszać linie, ale może też potasować swoje argumenty. I tak dalej. Skrzynka narzędziowa jest pełna !