Showing posts with label GS. Show all posts
Showing posts with label GS. Show all posts

Tuesday, August 11, 2009

wxErlang

There's another graphics library other than "gs" aka Graphical System which is an adaptation of wxWidgets otherwise known as wxErlang. If you have never tried using wxErlang to run your stuff then you might run into some problems.

Sadly, the documentation on this is pitifully little

For me, i got this error when i attempt to run the default wx libraries shipped with Erlang.

=ERROR REPORT==== 7-Jun-2009::12:17:09 ===
WX Failed loading "wxe_driver"@"/usr/local/lib/erlang/lib/wx-0.98.1/
priv/i386-apple-darwin9.6.0"
** exception error: {load_driver,"dlopen(/usr/local/lib/erlang/lib/
wx-0.98.1/priv/i386-apple-darwin9.6.0/wxe_driver.so, 2): Symbol not
found: __ZN10wxGLCanvas20MacVisibilityChangedEv\n Referenced from: /
usr/local/lib/erlang/lib/wx-0.98.1/priv/i386-apple-darwin9.6.0/
wxe_driver.so\n Expected in: flat namespace\n"}
in function wxe_server:start/0
in call from wx:new/1

If this is familiar to you, then i suggest you do the following
1. Read all of this
or if you are like me building wxErlang & BEAM emulator 5.7 from source
1. Download the wxErlang libraries from wxErlang website and unzip to dir wxMac-2.8.10
2. Change to that directory
3. Execute the following command:
./configure --with-opengl --enable-unicode --disable-shared --enable-graphics_ctx

4. Do the following in sequence:
make && make install
cd contrib/src/stc/
make && make install
Note that you might need to do a "sudo make install" if you use the default installation prefix which is /usr/local/{bin,lib, etc}
5. Assumed that you've download Erlang-OTP 13B source code and unzipped to a directory
6. Export the PATH variable such that the build directory to your wxErlang is right at the front of the PATH. e.g. export PATH=<wxErlang dir>:<rest of your path>
7. Build your erlang source code as per your preferences/needs as defined in the README

After all that is over, you should be able to launch your wxErlang programs.


Wednesday, November 7, 2007

Core Erlang + "GS" = GUI version of the "Insertion Sort"

In this article, i got another popular sorting algorithm commonly known as the "Insertion Sort". Basically, this sort an example of (a) in-place , (b) comparison-sort .You may wish to consult your favourite algorithm texts or visit the Wikipedia (I've heard its rather unreliable but i'm not so sure why). Again like all my previous articles, there are two parts to this: (a) Non-graphical, (b) Graphical version.

Here's the codes:

Filename: "isort.erl"
-module(isort).
-export([start/1]).
-copyright('Copyright (c) 2007 Raymond Tay').
-vsn('$Revision: 1').
%
%
% The insertion sort is a good middle-of-the-road choice for sorting lists of
% a few thousand items or less. The algorithm is significantly simpler than
% the shell sort, with only a small trade off in efficiency. At the same time
% the insertion sort is over twice as fast as the bubble sort and almost 40%
% faster than the selection sort. The insertion sort shouldn't be used for
% sorting lists larger than a couple thousands items or repetitive sorting
%of lists larger than a couple hundred items
%
% insertionSort(array A)
% for i = 1 to length[A]-1 do
% value = A[i]
% j = i-1
% while j >= 0 and A[j] > value do
% A[j + 1] = A[j]
% j = j-1
% A[j+1] = value
%

genNum(N,N,L,F,Num) -> [F(Num),L];
genNum(I,N,L,F,Num) -> Val = F(Num), genNum(I+1,N,[Val,L],F,Num).

for(N,N,F,L) -> Val = lists:nth(N,L), J = N - 1,T = lists:nth(J,L), F(J,L,Val,T);
for(I,N,F,L) -> Val = lists:nth(I,L), J = I - 1,T = lists:nth(J,L), L2 = F(J,L,Val,T), for(I+1,N,F,L2).

checkNInsert(Index,L,Value,T) when Index >= 1 andalso T > Value ->
{L1,L2} = lists:split(Index,L),
[_H|T1] = L2,
Temp1 = lists:flatten(lists:append([L1],[T])),
Temp2 = lists:append(Temp1, T1),
if
Index - 1 /= 0 ->
NewVal = lists:nth(Index - 1, Temp2),
checkNInsert(Index - 1, Temp2, Value, NewVal);
Index - 1 =:= 0 ->
checkNInsert(Index - 1, Temp2, Value, Value)
end;
checkNInsert(Index,L,Value,T) when Index =< 1 orelse T =< Value ->
{L1,L2} = lists:split(Index,L),
[_H|T1] = L2,
lists:append(lists:append(L1,[Value]),T1).

start(N) ->
L = lists:flatten(genNum(1,N,[],fun random:uniform/1, N)),
for(2, length(L), fun checkNInsert/4, L).

And next is for the graphical version

Filename: "isortgui.erl"
-module(isortgui).
-export([start/0]).
-copyright('Copyright (c) 2007 Raymond Tay').
-vsn('$Revision: 1').
%
% The insertion sort is a good middle-of-the-road choice for sorting lists of
% a few thousand items or less. The algorithm is significantly simpler than
% the shell sort, with only a small trade off in efficiency. At the same time
% the insertion sort is over twice as fast as the bubble sort and almost 40%
% faster than the selection sort. The insertion sort shouldn't be used for
% sorting lists larger than a couple thousands items or repetitive sorting
% of lists larger than a couple hundred items
%
% insertionSort(array A)
% for i = 1 to length[A]-1 do
% value = A[i]
% j = i-1
% while j >= 0 and A[j] > value do
% A[j + 1] = A[j]
% j = j-1
% A[j+1] = value
%
forL(N,N,{stretch,_N,_X}) -> [{stretch,_N,_X}];
forL(I,N,{stretch,_N,_X}) -> [{stretch,_N,_X}|forL(I+1,N,{stretch,_N,_X})].

for(N,N,F,L) -> {_,Val} = gs:read(dict:fetch({1,N},L),label), J = N - 1, {_,T} = gs:read(dict:fetch({1,J},L),label), {Val1,_} = string:to_integer(Val), {T1,_} = string:to_integer(T),F(J,L,Val1,T1);
for(I,N,F,L) -> {_,Val} = gs:read(dict:fetch({1,I},L),label), J = I - 1, {_,T} = gs:read(dict:fetch({1,J},L),label), {Val1,_} = string:to_integer(Val), {T1,_} = string:to_integer(T), D2 = F(J,L,Val1,T1), for(I+1,N,F,D2).

checkNInsert(Index,L,Value,T) when Index >= 1 andalso T > Value ->
ButId = dict:fetch({1,Index+1},L),
gs:config(ButId, [{label, {text, T}}]),
gs:config(ButId, [flash]),
sleep(50),
if
Index - 1 =:= 0 -> checkNInsert(0,L,Value,Value);
Index - 1 /= 0 ->
{_,Val} = gs:read(dict:fetch({1,Index -1},L),label),
{Val1,_} = string:to_integer(Val),
if
Val1 =< Value -> checkNInsert(Index - 1, L, Value, Value);
Val1 > Value -> checkNInsert(Index - 1, L, Value, Val1)
end
end;
checkNInsert(Index,L,Value,T) when Index =:= 0 orelse T =< Value ->
ButId = dict:fetch({1,Index+1},L),
gs:config(ButId, [{label, {text, Value}}]),
gs:config(ButId, [flash]),
L.

isort(Dict) ->
for(2, 50, fun checkNInsert/4, Dict). % Sort it for 2-to-<number of columns in GUI>

start() ->
D = dict:new(),
WH = [{width, 1000}, {height, 50}],
Win = gs:window(gs:start(), [{map, true}, {configure, true}, {title, "Insertion-Sort Algorithm"} |WH]),
XOpts = forL(1,50,{stretch,1,20}),
YOpts = [{stretch,1,20}],
gs:frame(packer, Win, [{packer_x, XOpts}, {packer_y, YOpts}]),
NewD = genBut(1,1,D),
gs:config(packer,WH),
dumpDict(NewD),
isort(NewD),
dumpDict(NewD),
io:format("algo done~n",[]),
loop().
%
%
% Generate the "button" GUI objects
%
genBut(Row,Col,Dict) when Col =< 50 ->
ButId = gs:button(packer, [{label, {text, random:uniform(50)}}, {pack_xy, {Col,Row}}]),
NewDict = dict:store({Row,Col}, ButId, Dict), % used later for GUI manipulation
genBut(Row,Col+1,NewDict);
genBut(Row,Col,Dict) when Col > 50 -> Dict.

%
% Pretty standard GUI-event loop
%
loop() ->
receive
{gs,_Id,destroy,_Data,_Arg} -> bye;
{gs,_Id,configure,_Data,[W,H|_]} ->
gs:config(packer, [{width,W}, {height,H}]), %refresh to initial size
loop();
_Other -> loop()
end.
%
% Pretty standard "sleep" function
%
sleep(T) ->
receive
after T -> ok
end.

%
% Dump the dictionary
%
dumpDict(D) ->
Keys = lists:sort(dict:fetch_keys(D)),
lists:foreach( fun({R,C}) -> Val = gs:read(dict:fetch({R,C},D),label), io:format("{~p,~p}->~p~n", [R,C,Val]) end, Keys).
While the algorithm is executing, you will notice that the buttons will flash every time it detects a re-positioning is required. Here is a screen shot and do let me know if you have any comments, it would be much appreciated; that applies to ideas as well :-)


Saturday, November 3, 2007

Core Erlang + "GS" = GUI version of the "BubbleSort"

Everyone who has studied Computer Science would know about the Bubble Sort algorithm. This is a simple sorting algorithm which runs at O(n^2). You may wish to consult your standard data structure text or the above hyperlink for further information.

Since this particular blog of mine is about Erlang and also i'm quite "hooked" to it, so again this article is about illustrating this algorithm implemented using Erlang. It's a fun exercise.

I have included source codes for running 2 versions: (a) Non-graphical and (b) Graphical.

%
% This is an attempt to create a GUI version of the "Bubble Sort"
%
% procedure bubblesort(A:list of unsorted items) defined as:
% do
% swapped := false
% for each i in 0 to length(A) -2 do
% if A[i] > A[i+1] then
% swap(A[i], A[i+1])
% swapped := true
% end if
% end for
% while swapped
% end procedure

-module(bsort).
-export([start/1, init/1]).
-copyright('Copyright (c) 2007 Raymond Tay').
-vsn('$Revision: 1').

start(N) -> spawn(bsort, init, [N]).

%
% Standard "for"-loop concept
%
for(N,N,Dict,F,Num) -> Val = F(Num), NewDict = dict:store(N,Val,Dict), NewDict;
for(I,N,Dict,F,Num) -> Val = F(Num), NewDict = dict:store(I,Val,Dict), for(I+1,N,NewDict,F,Num).

% Swaps the value but not the position of the record
%
swap({Pos1,Value1},{Pos2,Value2},Dict) ->
NewDict1 = dict:store(Pos1,Value2,Dict),
NewDict2 = dict:store(Pos2,Value1,NewDict1),
NewDict2.

%
% BubbleSort implementation
%
bsort(D,Swapped) when Swapped =:= false -> D;
bsort(D,Swapped) when Swapped =:= true ->
Len = erlang:length(dict:fetch_keys(D)),
{Again, NewDict} = checkNSwap(D,1,Len, false),
bsort(NewDict,Again).

%
% Check-N-Swap
%
checkNSwap(Dict,N,N,Again) -> {Again,Dict};
checkNSwap(Dict,I,N,Again) ->
Ele1 = dict:fetch(I,Dict),
Ele2 = dict:fetch(I+1,Dict),
if
Ele1 > Ele2 -> NewDict = swap({I,Ele1},{I+1,Ele2},Dict), checkNSwap(NewDict, I+1,N,true);
Ele1 =< Ele2 -> checkNSwap(Dict,I+1,N,Again)
end.

init(N) -> Dict = dict:new(),
NewDict = for(1,N,Dict, fun random:uniform/1, N),
dumpDict(bsort(NewDict,true)).


dumpDict(Dict) ->
Keys = lists:sort(dict:fetch_keys(Dict)),
lists:foreach(fun(X) -> io:format("{~p,~p} ...", [X,dict:fetch(X,Dict)]) end, Keys).

The next is the source code for the graphical version of the "Bubble Sort" and some screen-shots of the algorithm in action. I used an 25 x 25 "grid" composed of buttons (Will explore using the canvas when i have more time) and i tried the 100 x 100 "grid" but it didn't work out on my laptop as i had some resolution problems, but i think as an exercise a 25 x 25 was good enough for me :-)

-module(bsortgui).
-export([start/0]).
%
% BubbleSort implementation
%
bsort(D,Swapped) when Swapped =:= false -> D;
bsort(D,Swapped) when Swapped =:= true ->
{Again, NewDict} = checkNSwap(D,1,25, false),
bsort(NewDict,Again).

%
% Swaps the value but not the position of the record
%
swap({Pos1,Value1,ButId1},{Pos2,Value2,ButId2},Dict) ->
gs:config(ButId1,[{label, {text, ""}}]),
gs:config(ButId2,[{label, {text, ""}}]),
NewButId1 = dict:fetch({Value1,Pos2},Dict),
NewButId2 = dict:fetch({Value2,Pos1},Dict),
gs:config(NewButId1,[{label, {text, Value1}}]),
gs:config(NewButId2,[{label, {text, Value2}}]),
NewDict1 = dict:store(Pos1,{Value2,NewButId2},Dict),
NewDict2 = dict:store(Pos2,{Value1,NewButId1},NewDict1), NewDict2.

sleep(T) ->
receive
after T -> ok end.
%
% Check-N-Swap
%
checkNSwap(Dict,N,N,Again) -> {Again,Dict};
checkNSwap(Dict,I,N,Again) ->
{Ele1,ButId1} = dict:fetch(I,Dict),
{Ele2,ButId2} = dict:fetch(I+1,Dict),
%io:format("Col:~p,Row:~p~n", [I,Ele1]),
%io:format("Col:~p,Row:~p~n", [I+1,Ele2]),
if
Ele1 > Ele2 -> NewDict = swap({I,Ele1,ButId1},{I+1,Ele2,ButId2},Dict), sleep(300), checkNSwap(NewDict, I+1,N,true);
Ele1 =< Ele2 -> checkNSwap(Dict,I+1,N,Again)
end.


forL(N,N,{stretch,_N,_X}) -> [{stretch,_N,_X}];
forL(I,N,{stretch,_N,_X}) -> [{stretch,_N,_X}|forL(I+1,N,{stretch,_N,_X})].

%for(N,N,[H|_], D, F) -> F(H,D);
%for(I,N,[H|T], D, F) -> NewD = F(H,D), for(I+1,N,T,NewD,F).

genBut(Row,Col,Dict) when Row*Col =< 625 ->
if
Col =< 25 ->
ButId = gs:button(packer, [{label, {text, ""}}, {pack_xy, {Col,Row}}]),
NewDict = dict:store({Row,Col}, ButId, Dict), % used later for GUI manipulation
%io:format("genBut(), Row:~p, Col:~p, Id:~p~n", [Row,Col,ButId]),
genBut(Row,Col+1,NewDict);
Col > 25 -> genBut(Row+1, 1, Dict)
end;
genBut(Row,Col,Dict) when Row*Col > 625 -> Dict.

%
% Fill each column with exactly 1 random number
%
fillRand(Col,Dict) when Col =< 25 ->
Ran = random:uniform(25),
if
Col =< 25 ->
ButId = dict:fetch({Ran,Col},Dict),
gs:config(ButId, [{label, {text, Ran}}]),
NewDict = dict:store(Col, {Ran,ButId}, Dict), % used later for GUI manipulation
%io:format("Row:~p,Col:~p,Val:~p~n", [Ran,Col,Ran]),
fillRand(Col+1,NewDict)
end;
fillRand(Col,Dict) when Col > 25 -> Dict.



start() ->
D = dict:new(),
WH = [{width, 800}, {height, 800}],
Win = gs:window(gs:start(), [{map, true}, {configure, true}, {title, "BubbleSort Algorithm"} |WH]),
XOpts = forL(1,25,{stretch,1,15}),
YOpts = forL(1,25,{stretch,1,15}),
gs:frame(packer, Win, [{packer_x, XOpts}, {packer_y, YOpts}]),
NewD = genBut(1,1,D),
NewD2 = fillRand(1,NewD),
gs:config(packer,WH),
bsort(NewD2,true),
io:format("Done~n",[]),
loop().
%
% A typical loop for receiving messages
%
loop() ->
receive
{gs,_Id,destroy,_Data,_Arg} -> bye;
{gs,_Id,configure,_Data,[W,H|_]} ->
gs:config(packer, [{width,W},{height,H}]), %refresh to initial size
loop();
_Other -> loop()
end.

Below are some screenshots.



Let me know your comments if you got any :-)

Monday, October 29, 2007

Core Erlang + "GS" = GUI version of the "Sieve"

In this article, i want to demonstrate a bit more about the G.S. Previously, i wrote an extremely simple Erlang Window just to see how it easy it was, apparently it's not very difficult.

What i subsequently did was to combine the both the "GS" and the Sieve of Eratosthenes to produce a graphical version of the "sieving" problem. The point of this exercise was to illustrate how easy it was to code in Erlang once you have gotten used to its semantics, i had fun doing it.

Owing to my laptop's screen resolution, i could only manage a 25-by-25 grid but that's not the point of this exercise. Here are some screen shots and a working code (Code needs to be smoothen though, let me know your comments)

%
% This is an attempt to create a GUI version of the "Sieve of Erasothenes'
%
%
-module(sievegui).
-export([start/0, init/1]).
-copyright('Copyright (c) 2007 Raymond Tay').
-vsn('$Revision: 1').
%
% The following generates a list of multiples-of-Base
% e.g. To generate multiples of 3 less than 100, enter "sieve:genmulti(0,3,100)"
% and you get [9,12,15,18|...]
%
genmulti(Index,Base,Limit) when (Base*Base+Index*Base) > Limit -> [];
genmulti(Index,Base,Limit) when (Base*Base+Index*Base) =< Limit -> [Base*Base+Index*Base | genmulti(Index+1,Base,Limit) ].

sleep(T) ->
receive
after T -> ok
end.
%
% Obtains the GS's "object id" and manipulates the display
%
filterDisplay(ObjId,List) ->
{_,ObjValue} = gs:read(ObjId, label),
{IntValue,X} = string:to_integer(ObjValue),
Result = lists:member(IntValue,List),
if
Result =:= true -> gs:config(ObjId,[{label, {text, ""}}]);
Result =:= false -> ok
end,
sleep(50).
% filterDisplay(ObjId,List) ->
% {_,ObjValue} = gs:read(ObjId, label),
% Result = lists:member(ObjValue,List),
% if
% Result =:= true -> gs:config(ObjId,[{label, {text, ""}}])
% end.

removeMultiples(Index, List, Limit, Dict) when Index /= erlang:length(List) ->
Head = lists:nth(Index,List),
RemoveList = genmulti(0,Head,Limit),
Keys = dict:fetch_keys(Dict),
lists:foreach( fun(X) -> filterDisplay(X,RemoveList) end, Keys),
NewList = List -- RemoveList,
removeMultiples(Index+1, NewList, Limit, Dict);
removeMultiples(Index, List, _, _) when Index =:= erlang:length(List) -> List.


%
% A standard Erlang "for"-loop
%
for(N,N,F) -> F();
for(I,N,F) -> F(),for(I+1,N,F).

forL(N,N,{stretch,_N,_X}) -> [{stretch,_N,_X}];
forL(I,N,{stretch,_N,_X}) -> [{stretch,_N,_X}|forL(I+1,N,{stretch,_N,_X})].
%
% start() -> You can call this if you wish; the only difference between this and init() is that start() starts
% a spawned process
%
start() -> spawn(gsdemo, init, [625]).

%
% Generates the GUI for the button
% where the label for each button is that of incremental number
%
genBut(Row,Col,Text,Dict) when Row*Col =< 625 ->
if
Col =< 25 ->
%io:format("R:~p,C:~p,T:~p~n", [Row,Col,erlang:integer_to_list(Text,10)]),
ButId = gs:button(packer, [{label, {text, erlang:integer_to_list(Text,10)}}, {pack_xy, {Col,Row}}]),
NewDict = dict:store(ButId, ButId, Dict),
NewText = Text+1,
genBut(Row,Col+1, NewText, NewDict);
Col > 25 -> genBut(Row+1, 1, Text, Dict)
end;
genBut(Row,Col,_Text, Dict) when Row*Col > 625 -> Dict.

%
% init() - You can call this if you wish
%
init(Num) ->
_Dict = dict:new(), % process dictionary
WH = [{width, 800}, {height, 800}],
Win = gs:window(gs:start(), [{map, true}, {configure, true}, {title, "Sieve of Erasothenes"} |WH]),
XOpts = forL(1,25,{stretch,1,8}),
YOpts = forL(1,25,{stretch,1,8}),
gs:frame(packer, Win, [{packer_x, XOpts}, {packer_y, YOpts}]),
NewDict = genBut(1,1,2,_Dict),
gs:config(packer, WH), %refresh to initial size
List = lists:seq(2,Num),
FinalList = removeMultiples(1, List, lists:max(List), NewDict),
loop().
%
% A typical loop for receiving messages
%
loop() ->
receive
{gs,_Id,destroy,_Data,_Arg} -> bye;
Other -> loop()
end.
There are three screenshots below of this application to illustrate the program sieving through the numbers

That's it, all comments are welcome.

Friday, October 5, 2007

Using the Graphical System a.k.a "gs" module in Erlang

In this article, i want to present some basic usage of the graphical system otherwise known as the Erlang module "gs". The pre-requisites is the requirement for Tcl/Tk to be installed on your Linux system, otherwise you will get the error "{error,backend_died}" when you invoke the "gs:start()" and lastly include the path to your linux user so that Erlang can locate the "tk".

I have a contrived example of a simple Erlang GUI

-module(simple_window).
-export([start/0]).

start() ->
Id = gs:start(),
Win = gs:create(window, Id, [{width, 200}, {height, 100}],
Butt = gs:create(button, Win, [{label, {text, "Press Me"}}, {x, 0}]),
Butt2 = gs:create(button, Win, [{label, {text, "Stop"}}, {x, 100}]),
gs:config(Win, {map, true}),
loop(Butt, Butt2, Win).

loop(Butt, Butt2, Win) ->
receive
{gs, Butt, click, Data, Args} ->
io:format("Hello There~n", []),
loop(Butt);
{gs, Butt2, click, Data, Args} ->
gs:destroy(Win)
end.

What just happened is this
  1. A graphics server was created via the "gs:start()"
  2. A window was created with the defined width and height
  3. A button was created inside the window with a text
  4. A event-loop was created that will receive the GUI-events from the user
That's about the amount of effort u need to create a simple GUI window. The figure shows a screenshot
From the screenshot, if you keep hitting the button "Press Me" then the Erlang shell will display "Hello There" and if you hit the button "Stop" then the window will close cleanly