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.

Sunday, October 14, 2007

Erlang Hot Code Swapping

In this post, i'm going to repeat Joe Armstrong's technique of hot code swapping using Erlang. It's a extremely powerful technique which basically allows you to swap/interchange code without restarting the server(s).Joe Armstrong, in his book, demonstrated the technique of hot swapping and i would like to repeat that with a J2EE twist to it. To my knowledge, most J2EE container cannot perform this smoothly yet; however, do let me know if my information is not correct.

What i have is a simple Stateless Session EJB (Enterprise Java Bean). The J2EE container model uses a callback invocation + client-server architecture so that the container can run both client and lifecycle functions.

Filename: "Converter.java" --- Actual EJB remote class
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
import java.math.*;

public interface Converter extends EJBObject {
public BigDecimal dollarToYen(BigDecimal dollars) throws RemoteException;
public BigDecimal yenToEuro(BigDecimal yen) throws RemoteException;
}

Filename: "ConverterHome.java" --- Actual EJB Home class
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;

public interface ConverterHome extends EJBHome {
Converter create() throws RemoteException, CreateException;
}

Filename: "ConverterBean.java" --- Actual EJB class

import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import java.math.*;

public class ConverterBean implements SessionBean {

BigDecimal yenRate = new BigDecimal("121.6000");
BigDecimal euroRate = new BigDecimal("0.0077");

public BigDecimal dollarToYen(BigDecimal dollars) {
BigDecimal result = dollars.multiply(yenRate);
return result.setScale(2,BigDecimal.ROUND_UP);
}

public BigDecimal yenToEuro(BigDecimal yen) {
BigDecimal result = yen.multiply(euroRate);
return result.setScale(2,BigDecimal.ROUND_UP);
}

public ConverterBean() {}
public void ejbCreate() {}
public void ejbRemove() {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void setSessionContext(SessionContext sc) {}
}
So, how do you accomplished the above to the Erlang equivalent? The toughest part is building a framework that will invoke the lifecycle methods like those ejbXXX as well as conformation to the specifications laid out by the J2EE Community and i will skip that part, for now and hence, i will concentrate on the client-server part as well as hot code swapping. Below is my attempt at the above mentioned J2EE implementation.

Filename: "callback.erl"
-module(callback).
-export([init/0, ejbActivate/0, ejbPassivate/0, ejbRemove/0, dollarToYen/1, yenToEuro/1, handle/2]).
-import(container, [rpc/2]).

%% client routines
dollarToYen(Dollars) -> rpc(ejbserver, {convertToYen, Dollars}).
yenToEuro(Yen) -> rpc(ejbserver, {convertToEuro, Yen}).
ejbActivate() -> rpc(ejbserver, {ejbactivate}).
ejbPassivate() -> rpc(ejbserver, {ejbpassivate}).
ejbRemove() -> rpc(ejbserver, {ejbremove}).

%% callback routines
init() -> dict:new().

handle({convertToYen, Dollars}, Dict) -> { Dollars * 126, Dict};
handle({ejbactivate}, Dict) -> { ejbActivate , Dict};
handle({ejbpassivate}, Dict) -> { ejbPassivate , Dict};
handle({ejbremove}, Dict) -> { ejbRemove , Dict};
handle({convertToEuro, Yen}, Dict) -> {Yen * 0.0077, Dict}.

Filename: "container.erl"
-module(container).
-export([start/2, rpc/2, swap_code/2]).

start(Name, Mod) ->
register(Name, spawn(fun() -> loop(Name, Mod, Mod:init()) end)).

swap_code(Name,Mod) -> rpc(Name, {swap_code, Mod}).

%
% Standard code for abstracting the "RPC-call" layer
%
rpc(Name, Request) ->
Name ! {self(), Request},
receive
{Name, Response} -> Response
end.

%
% Standard code for looping and waiting for messages from clients
%
loop(Name, Mod, OldState) ->
receive
{From, {swap_code, NewCallbackMod}} ->
From ! {Name, ack},
loop(Name, NewCallbackMod, OldState);
{From, Request} ->
{Response, NewState} = Mod:handle(Request,OldState),
From ! {Name, Response},
loop(Name, Mod, NewState)
end.

So how do you run it ? Refer to the figure below
I shall briefly explain what i did,
1/ compile the "server"
2/ compile the "callback" a.k.a. EJB
3/ start up the "server"
4/ invoke the callback / EJB to run the interface functions




So, the next thing is how do i do hot code swapping without bringing down the server? What you need to do first is to decide what your replacement code is going to be and swap it with the code that was just running. E.g. let's assume that i have decided to replace the callback.erl with another code callback2.erl and i want to replace the former with the latter.

Filename: "callback2.erl"
-module(callback2).
-export([init/0, ejbActivate/0, ejbPassivate/0, ejbRemove/0, dollarToYenSpecial/1, yenToEuroSpecial/1, handle/2]).
-import(container, [rpc/2]).

%% client routines
dollarToYenSpecial(Dollars) -> rpc(ejbserver, {convertToYen, Dollars}).
yenToEuroSpecial(Yen) -> rpc(ejbserver, {convertToEuro, Yen}).
ejbActivate() -> rpc(ejbserver, {ejbactivate}).
ejbPassivate() -> rpc(ejbserver, {ejbpassivate}).
ejbRemove() -> rpc(ejbserver, {ejbremove}).

%% callback routines
init() -> dict:new().

handle({convertToYen, Dollars}, Dict) -> { Dollars * 126 * 126, Dict};
handle({ejbactivate}, Dict) -> { ejbActivate , Dict};
handle({ejbpassivate}, Dict) -> { ejbPassivate , Dict};
handle({ejbremove}, Dict) -> { ejbRemove , Dict};
handle({convertToEuro, Yen}, Dict) -> {Yen * 0.0077 * 0.0077, Dict}.
The changes are highlighted in bold for easy viewing. After, you need to compile it and swap it with the running code. Note that the Mod:init() does not run again. Refer to the figure below for a sample hot code swapping.









I hope this demonstrates how powerful Erlang can be and possibly a replacement language for Java and the like?

Saturday, October 6, 2007

Sieve of Eratosthenes

People whom studied computer science has heard of the "Sieve of Eratosthenes" and i took the implementation in Erlang as an exercise and collected the run-times of the program to determine the number of primes less than 120, 1000, 10000, 100000 and 1000000.


Filename: "sieve.erl"
-module(sieve).
-export([findPrimes/1, genmulti/3, removeMultiples/3]).

%
% 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) =<> [Base*Base+Index*Base | genmulti(Index+1,Base,Limit) ].

removeMultiples(Index, List, Limit) when Index /= erlang:length(List) ->
Head = lists:nth(Index,List),
NewList = List -- genmulti(0,Head,Limit),
removeMultiples(Index+1, NewList, Limit);
removeMultiples(Index, List, _) when Index =:= erlang:length(List) -> List.

findPrimes(Num) -> List = lists:seq(2,Num),
statistics(runtime),
statistics(wall_clock),
FinalList = removeMultiples(1, List, lists:max(List)),
{_, Time1} = statistics(runtime),
{_, Time2} = statistics(wall_clock),
io:format("Total discovered primes:~w~n", [erlang:length(FinalList)]),
io:format("Runtime:~w(s) Wall-clock Time:~w(s)~n", [Time1/1000, Time2/1000]),
lists:foreach( fun(X) -> io:format("~w, ", [X]) end, FinalList).

To run this, there are a few ways you can do this in Erlang but the most common is the following:
1/ Copy-paste the code into a file of your choice, in my case its "sieve.erl"
2/ Start a Erlang shell
3/ Compile the program via "c(sieve)."
4/ Execute the program via "sieve:findPrimes(120)" which is to find the number of primes numbers less than or equal to 120.

My program will reveal how many primes have been discovered and the computation time it took and you can counter check the number of primes discovered against this site How Many Primes Are There?

Finally, the run-times for discovering the number of primes less than 120, 1000, 10000, 100000 and 1000000 are displayed below.


sieve:findPrimes(120).
Total discovered primes:30
Runtime:0.00000e+0(s) Wall-clock Time:0.00000e+0(s)

sieve:findPrimes(1000).
Total discovered primes:168
Runtime:1.00000e-2(s) Wall-clock Time:9.00000e-3(s)

sieve:findPrimes(10000).
Total discovered primes:1229
Runtime:0.290000(s) Wall-clock Time:0.295000(s)

sieve:findPrimes(100000).
Total discovered primes:9592
Runtime:29.8900(s) Wall-clock Time:30.0060(s)

sieve:findPrimes(1000000).
Total discovered primes:78498
Runtime:3025.86(s) Wall-clock Time:3042.31(s)

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