Tuesday, February 17, 2009

Ch8, Ex2

I.Well, have a look at the kernel transform of the given program
local X in
local Y in
Y = X+1
{Exchange C X Y}
end
end

Now its clear to see that X is unbound and above program will keep on waiting for X to bind(that'll never happen) at line Y=X+1 and will never execute Exchange. Here is the program with a simple fix:
L = {NewLock}
lock L then X Y in
{Exchange C X Y}
Y = X+1
end

II. The simple fix that I have given above will not work in a language that doesn't have dataflow variables because it is *using* dataflow behavior of variable Y to work.

III. Another fix that doesn't use dataflow variables and hence, is possible in a language without dataflow variables:
L = {NewLock}
lock L then
C:=@C+1
end

Ch8, Ex1

Possible number of interleaving for n threads with k operations each:

(nk)! / (k!)^n

n^(nk + 1/2)
= -----------------
(2k.PI)^(n-1)/2

Ch7, Ex8 (todo)

todo

Ch7, Ex7 (tbd)

todo

Ch7, Ex6

Sequential stateful without short circuiting:
An array N elements is created, all initialized to true. We start iterating over the array from index one, keep on setting values to false whenever (Count mod K) is 0. We keep track of number of survivors also and as soon as it reaches 1, we return the closest array index which is still true( or alive). As we never remove elements from array (no short circuiting).
declare
fun {Josephus N K}
A = {NewArray 1 N true}
fun {NextI I} (I mod N)+1 end
fun {Iter N C I}
if N==1 andthen {Array.get A I}==true then I
elseif N==1 then {Iter N C {NextI I}}
elseif {Array.get A I}==true andthen (C mod K)==0 then
{Array.put A I false}
{Iter N-1 C+1 {NextI I}}
elseif {Array.get A I}==true then
{Iter N C+1 {NextI I}}
else {Iter N C {NextI I}}
end
end
in
{Iter N 1 1}
end

Sequential stateful with short circuiting:
The only difference here is that, we use a dictionary instead of array and remove(rather than setting value to false) whenever (Count mod K) is 0. Structurally both these programs are the same.
declare
fun {Josephus N K}
D = {NewDictionary}
for I in 1..N do D.I:=t end
fun {NextI I} (I mod N)+1 end
fun {Iter N C I}
if N==1 andthen {Dictionary.condGet D I f}==t then I
elseif N==1 then {Iter N C {NextI I}}
elseif {Dictionary.condGet D I f}==t
andthen (C mod K)==0 then
{Dictionary.remove D I}
{Iter N-1 C+1 {NextI I}}
elseif {Dictionary.condGet D I f}==t then
{Iter N C+1 {NextI I}}
else {Iter N C {NextI I}}
end
end
in
{Iter N 1 1}
end

Structure of Active object based version from the book:
Here we basically create a doubly linked list of Victim active objects and pass the kill(I) token. Every Vicim on the list passes the token to next object in the list(and also is removed if I mod K is 0). This way the token keeps on circulating untill there is just one item(survivor) remaining in the list.

Apart from the models used, The main differences between the above versions and those there in the book, are in the code size and the iteration. In above versions iterations is done explicitly while in the versions from the book iteration is implicit due to the message passing technique.

b) I'm passing the analysis of finding the (n,k) region for which short circuiting is helpful because It's easy to understand by logic only. Larger the N and smaller the K(but greater than 1 or else there won't be second iteration and hence no use of shortcircuiting), more is the advantage of short circuiting as less number of items are to be traversed in subsequenct iterations one after another. If short circuiting was not there then we have to traverse all N items in all the iterations no matter how many of them are alive.
However, in above two versions the version with short circuiting is actually slower but that is because Dictionary operations are much more expensive than Array operations and that shadows the advantage bought by short circuiting.

I used following code to find about the timings of the three versions.
for N in 1000..1050 do
for K in 100..110 do T1 T2 R in
T1 = {Property.get 'time.total'}
R = {Josephus N K}
{Wait R}
T2 = {Property.get 'time.total'}
{Show josephus(n:N k:K result:R timeTaken:(T2-T1))}
end
end

The version that uses OO model was hovering around 130ms, declarative concurrent version(fastest) was hovering aroung 70ms and declarative sequential model(slowest) was taking around 210ms. Declarative sequential model is slow because of the Dictionary operations as they're expensive.

Asymptotically all three versions have the same time complexity as they're effectively doing the same thing which is to keep on following the list(killing the unfortunates on the way and removing them from the list) circularly unless there is only one survivor left. Note: The word list is used in a very loose sense, its not the list type of oz.

=========================================================================
A declarative sequential solution to josephus problem...While reading the book I wrote this one(nothing fancy).We start with a list [1..N], keep on iterating over it in circular fashion and keep on removing every Kth item untill there is just one element left and that last element is the survivor.
declare Josephus
local
%Generates list [1 2 3..N]
%Usage: {GenerateList N nil}
fun {GenerateList N A}
if N>0 then {GenerateList N-1 N|A}
else A end
end
in
fun {Josephus N K}
% N: number of survivors
% C: count
% Xs: Active list of survivors
% Ys: ongoing list of survivors from Xs
fun {Iter N C Xs Ys}
if N==1 then Xs.1
else
case Xs of X|nil andthen (C mod K)==0 then
{Iter N-1 C+1 {Reverse Ys} nil}
[] X|nil then
{Iter N C+1 {Reverse X|Ys} nil}
[] X|Xr andthen (C mod K)==0 then
{Iter N-1 C+1 Xr Ys}
[] X|Xr then
{Iter N C+1 Xr X|Ys}
end
end
end
in
{Iter N 1 {GenerateList N nil} nil}
end
end

Ch7, Ex5

I- Synchronous RMI
declare
class ServerProc
meth init
skip
end
meth send(Msg)
case Msg of calc(X Y) then
Y=X*X+2.0*X+2.0
end
end
end
Server = {NewActive ServerProc init}

declare
class ClientProc
meth init
skip
end
meth send(Msg)
case Msg
of work(Y) then
Y1 Y2 in
{Server send(calc(10.0 Y1))}
{Wait Y1}
{Server send(calc(20.0 Y2))}
{Wait Y2}
Y=Y1+Y2
end
end
end
Client = {NewActive ClientProc init}

{Browse {Client send(work($))}}

II- Asynchronous RMI
Only ClientProc is changed, everything else remains same as the synchronous RMI.
declare
class ClientProc
meth init
skip
end
meth send(Msg)
case Msg
of work(Y) then
Y1 Y2 in
{Server send(calc(10.0 Y1))}
{Server send(calc(20.0 Y2))}
Y=Y1+Y2
end
end
end

III- RMI with callback(with thread)
declare
class ServerProc
meth init
skip
end
meth send(Msg)
%{Browse server#Msg}
case Msg
of calc(X Y Client) then
X1 D in
{Client send(delta(D))}
X1=X+D
Y=X1*X1+2.0*X1+2.0
end
end
end
Server = {NewActive ServerProc init}

declare
class ClientProc
meth init
skip
end
meth send(Msg)
%{Browse client#Msg}
case Msg
of work(Z) then
Y in
{Server send(calc(10.0 Y self))}
%here we don't need to create another
%thread as we're passing self and not
%Client
Z=Y+100.0
[] delta(D) then
D=1.0
end
end
end
Client = {NewActive ClientProc init}

{Browse {Client send(work($))}}

IV- RMI with callback (using record continuation)
declare
class ServerProc
meth init
skip
end
meth send(Msg)
%{Browse server#Msg}
case Msg
of calc(X Client Cont) then
X1 D Y in
{Client send(delta(D))}
X1=X+D
Y=X1*X1+2.0*X1+2.0
{Client send(Cont#Y)}
end
end
end
Server = {NewActive ServerProc init}

declare
class ClientProc
meth init
skip
end
meth send(Msg)
%{Browse client#Msg}
case Msg
of work(?Z) then
{Server send(calc(10.0 self cont(Z)))}
[] cont(Z)#Y then
Z=Y+100.0
[] delta(?D) then
D=1.0
end
end
end
Client = {NewActive ClientProc init}

{Browse {Client send(work($))}}

V- RMI with callback (using procedure continuation)
Only ClientProc is changed, everything else remains same as the record continuation technique
class ClientProc
meth init
skip
end
meth send(Msg)
%{Browse client#Msg}
case Msg
of work(?Z) then
C = proc {$ Y} Z=Y+100.0 end
in
{Server send(calc(10.0 self cont(C)))}
[] cont(C)#Y then
{C Y}
[] delta(?D) then
D=1.0
end
end
end

VI- Error Reporting
class ServerProc
meth init
skip
end
meth send(Msg)
case Msg
of sqrt(X Y E) then
try
Y={Sqrt X}
E=normal
catch Exc then
E=exception(Exc)
end
end
end
end
Server = {NewActive ServerProc init}

%It can be used as
{Server send(sqrt X Y E)}
case E of exception(Exc) then
raise Exc end end

VII- Asynchronous RMI with callback
declare
class ServerProc
meth init
skip
end
meth send(Msg)
case Msg
of calc(X ?Y Client) then
X1 D in
{Client send(delta(D))}
thread
X1=X+D
Y=X1*X1+2.0*X1+2.0
end
end
end
end
Server = {NewActive ServerProc init}

declare
class ClientProc
meth init
skip
end
meth send(Msg)
case Msg
of work(?Y) then
Y1 Y2 in
{Server send(calc(10.0 Y1 self))}
{Server send(calc(20.0 Y2 self))}
thread Y=Y1+Y2 end
[] delta(?D) then
D=1.0
end
end
end
Client = {NewActive ClientProc init}

{Browse {Client send(work($))}}

VIII-Double Callbacks
declare
class ServerProc
meth init
skip
end
meth send(Msg)
case Msg
of calc(X ?Y Client) then
X1 D in
{Client send(delta(D))}
thread
X1=X+D
Y=X1*X1+2.0*X1+2.0
end
[] serverdelta(?S) then
S=0.01
end
end
end
Server = {NewActive ServerProc init}

declare
class ClientProc
meth init
skip
end
meth send(Msg)
case Msg
of work(Z) then
Y in
{Server send(calc(10.0 Y self))}
thread Z=Y+100.0 end
[] delta(?D) then S in
{Server send(serverdelta(S))}
thread D=1.0+S end
end
end
end
Client = {NewActive ClientProc init}

{Browse {Client send(work($))}}

Ch7, Ex4

To allow multiple inheritance(for 1 or more), I have just generalized the "From" function from the book. Instead of taking fixed number of classes to be inherited it now takes a list of classes to be inherited.
I'm redoing the Account, LoggedAccount example from section 7.3.2 to show how to achieve static binding with the object system of section 7.6 . However, It doesn't look very clean solution... will change it once I can think something else.
For better understanding, Please read the code below along with the embedded comments.

%Helpers-----------------------------------------------------
declare NewWrapper Wrap Unwrap Union Inter Minus LogObj

LogObj = {New class $
attr entries
meth init
entries:=nil
end
meth addEntry(X)
entries:=X|(@entries)
end
meth getEntries(?X)
X={List.reverse @entries}
end
meth clear
entries:=nil
end
end
init}

proc {NewWrapper ?W ?U}
Key={NewName}
in
fun {W X}
fun {$ K} if K==Key then X end end
end
fun {U Y}
{Y Key}
end
end

{NewWrapper Wrap Unwrap}

%Download Set.oz from book's suppliment site then
%create ozc file by running following command
%$ozc -c Set.oz
%CHANGE PATH
declare
[Set]= {Module.link ['/path/Set.ozf']}
Union=Set.union
Inter=Set.inter
Minus=Set.minus

declare New2
fun {New2 WClass InitialMethod}
State Obj Class
in
Class={Unwrap WClass}
State = {MakeRecord s Class.attrs}
{Record.forAll State proc {$ A} {NewCell _ A} end}
proc {Obj M}
{Class.methods.{Label M} M State Obj}
end
{Obj InitialMethod}
Obj
end
%Helpers finished-------------------------------------------------

%New From to allow multiple inheritence,
%Returns new class record whose base defn
%is BaseC and inherits all classes in
%list Classes
declare
fun {From BaseC Classes}
c(methods:M attrs:A) = {Unwrap BaseC}
ParentMeths = {Map Classes
fun {$ X}
c(methods:M attrs:_)={Unwrap X}
in M
end}
ParentMethArities = {Map ParentMeths
fun {$ M} {Arity M} end}
ParentAttrs = {Map Classes
fun {$ X}
c(methods:_ attrs:A)={Unwrap X}
in A
end}
ConfMeth=if {List.length Classes}>1 then
{Minus {FoldL ParentMethArities
fun {$ MA1 MA2} {Inter MA1 MA2} end
ParentMeths.1} {Arity M}}
else
nil end
ConfAttr=if {List.length Classes}>1 then
{Minus {FoldL ParentAttrs
fun {$ A1 A2} {Inter A1 A2} end
ParentAttrs.1} A}
else
nil end
in
if ConfMeth\=nil then
raise illegalInheritance(methConf:ConfMeth) end
end
if ConfAttr\=nil then
raise illegalInheritance(attrConf:ConfAttr) end
end
{Wrap c(methods:{Adjoin {FoldL ParentMeths
fun {$ M1 M2}
{Adjoin M1 M2}end
nil} M}
attrs:{Union {FoldL ParentAttrs
fun {$ A1 A2}
{Union A1 A2} end
nil} A})}
end

%Account,LoggedAccount example
declare Account
local
Attrs = [balance]
MethodTable = m(init:Init
transfer:Transfer
getBal:GetBal
batchTransfer:BatchTransfer)
proc {Init M S Self}
init(Bal) = M
in
(S.balance):=Bal
end

proc {Transfer M S Self}
transfer(Amt) = M
in
(S.balance):=Amt+@(S.balance)
end

proc {GetBal M S Self}
getBal(Bal) = M
in
Bal = @(S.balance)
end

proc {BatchTransfer M S Self}
batchTransfer(AmtList) = M
in
for A in AmtList do
{Self transfer(A)} end
end
in
Account = {Wrap c(methods:MethodTable attrs:Attrs)}
end

% LoggedAccount inherits Account
declare LoggedAccountBase
local
Attrs = nil
MethodTable = m(transfer:Transfer)
proc {Transfer M S Self}
{LogObj addEntry(M)}
%----------Static Binding----------
%its fair to know about the superclasses at
%the time of defining the subclass
{{Unwrap Account}.methods.transfer M S Self}
end
in
LoggedAccountBase = {Wrap c(methods:MethodTable
attrs:Attrs)}
end

%Test
local
LoggedAccClass
LoggedAccObj
in
{LogObj clear}
LoggedAccClass = {From LoggedAccountBase [Account]}
LoggedAccObj = {New2 LoggedAccClass init(0)}
{LoggedAccObj transfer(100)}
{LoggedAccObj transfer(200)}
{LoggedAccObj transfer(300)}
%This prints the above transactions that means the
%Transfer code from LoggedAccount is executed
{Browse {LogObj getEntries($)}}
%This prints the balance=600(100+200+300) that means
%static binding worked and Transfer code from Account
%was executed.
{Browse {LoggedAccObj getBal($)}}
end