Az R programozási nyelv

Példaprogramok

Mátrix szorzás


Feladat: Mátrixszorzás megvalósítása párhuzamos programmal.
Szerző: Fóthi Áron
Készítés éve: 2011
Használt fejlesztőkörnyezet:
Az algoritmus implementálásához, és a tesztmátrix létrehozásához: R 2.12.2 és az Rdsm csomag
A grafikus futtató környezethez: VS 2010, statconnDCOM
A párhuzamos mátrix szorzást a matmul függvényben implementáltam:
matmul <- function(m1, m2, prd) { myid <- myinfo$myid k <- if(class(m1) == "big.matrix") dim(m1)[2] else m1$size[2] chunksize <- floor(k/myinfo$nclnt) firstcol <- 1 + (myid-1) * chunksize if(myid == myinfo$nclnt) lastcol <- k else lastcol <- firstcol + chunksize - 1 prd[,firstcol:lastcol] <- m1[,] %*% m2[,firstcol:lastcol] barr() }

Az algoritmus a második mátrix oszlopait felosztja szálak között, és ezeket a részmátrixokat szorozza össze az első mátrixal. A szorzatok eredménye a közös prd mátrixba kerül. A bar() függvény biztosítja, hogy a szálak egyszerre érjenek véget.
A test függvény a létrehozza és kitölti az összeszorzandó mátrixokat, és felhívja a matmul függvényt.
test <- function(size, pr=TRUE) { long<-size * size mx <- matrix(1:long,nrow=size) newbm("ma","double",size,size,mx) newbm("mb","double",size,size,mx) newbm("mc","double",size,size,mx) matmul(ma,mb,mc) if (myinfo$myid == 1) if(pr) print(mc[,]) else mc[,] }

Az első kliens szál kiírja a mátrix tartalmát a konzolra.
A pr paraméterrel mondhatjuk meg, hogy végrehajsa-e az előző lépést, amire majd a grafikus futtatókörnyezetből való futtatásnál lesz szükség.
A program futtatása
-Nyiss az indítandó szálakkal megyegyező számú R Console-t, plussz egyet az Rdsm szerver indításához.
-Töltsd be az Rdsm és a bigmemory csomagokat
> library(Rdsm) > library(bigmemory)

-Indítsd el a szervert (N az eliindítandó szálak száma)
> srvr(port=2000,ncon=N)

-Az összes kliens szálon töltsd be az Rdsm és a bigmemory csomagokat
> library(Rdsm) > library(bigmemory)

-olvastasd be a scriptet
>source("MatMul.R")

-Inicializáld a szálakat
>init()

-Futtasd a test() függvényt (M a mátrix dimenziója)
>test(M)
Mivel az előző lépések végrehajtása elég körülményes, és a kézi indítások miatt több időt vesztünk, mint amennyit nyerhetünk a párhuzamos futtatással, érdemes írni egy futtató programot, amely elvégzi helyettünk ezeket a lépéseket.
Ehhez a legfontosabb eszköz a statconnDCOM. Lehetővé teszi R scriptek beágyazását .COM-os környezetbe. (Nem része az R-nek! Külön kell telepíteni)
A következő példa azt szemlélteti, hogy hogyan lehet ezt megvalósítan C# .NET-et választva, ráadásul párhuzamos megoldással.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Windows.Forms;
statconnDCOM
using STATCONNECTORCLNTLib; using StatConnectorCommonLib; using STATCONNECTORSRVLib; namespace R_Test { class R { protected static List threads; protected static Dictionary connectors; protected static double[,] d; public static int size; static Form1 m_form;

Minden szálhoz hozzárendelünk egy connectort
public R(int szalakSzama, Form1 form) { m_form = form; ewh = new EventWaitHandle(false, EventResetMode.ManualReset); threads = new List(); connectors = new Dictionary(); threads.Add(new Thread(DoServerWork)); threads.First().IsBackground = true; connectors.Add(0, new StatConnector()); threads.First().Start(szalakSzama); Thread.Sleep(200); for (int i = 1; i < szalakSzama + 1; i++) { Thread thread = new Thread(DoWork); thread.IsBackground = true; connectors.Add(i, new StatConnector()); Thread.Sleep(200); thread.Start(i); threads.Add(thread); } } public static EventWaitHandle ewh;

Elindítjuk a szervert
protected static void DoServerWork(object szalakSzama) { try { connectors.First().Value.Init("R"); connectors.First().Value.EvaluateNoReturn("library(Rdsm)"); connectors.First().Value.EvaluateNoReturn("library(bigmemory)"); connectors.First().Value.EvaluateNoReturn(string.Format("srvr(port=2000,ncon={0})", szalakSzama)); } catch (Exception ex) { } }

Elindítjuk a klienseket.
Ha az első kliens végrehajtotta a függvényt, akkor a connector Evaluate függvényének segítségével vissza tudjuk kapni az R töl a szorzás eredményét.
protected static void DoWork(object index) { try { connectors[(int)index].Init("R"); connectors[(int)index].EvaluateNoReturn("library(Rdsm)"); connectors[(int)index].EvaluateNoReturn("library(bigmemory)"); string matmul = System.Environment.CurrentDirectory + "/MatMul.R"; string csere = matmul.Replace('\\', '/'); connectors[(int)index].EvaluateNoReturn(string.Format("source(\"{0}\")", csere)); connectors[(int)index].EvaluateNoReturn("init()"); if ((int)index == threads.Count-1) m_form.Invoke(m_form.ThreadsStarted); for (;;) { ewh.WaitOne(); if ((int)index == 1) { d = (double[,])connectors[(int)index].Evaluate(string.Format("test({0}, FALSE)", size)); m_form.Invoke(m_form.DelegateThreadFinished, new Object[] { d }); ewh.Reset(); } else { connectors[(int)index].EvaluateNoReturn(string.Format("test({0}, FALSE)", size)); } } } catch (Exception ex) { } } } }

A teljes kód megtalálható a példaprogramok között.