DEGREE PROJECT, IN COMPUTER SCIENCE , FIRST LEVEL STOCKHOLM, SWEDEN 2015 Effektiva Lagringsmetoder för Glesa Matriser DANI POTRUS KTH ROYAL INSTITUTE OF TECHNOLOGY www.kth.se Effektiva Lagringsmetoder för Glesa Matriser En studie av glesa matrisers lagringsmetoder med fokus på en numerisk algoritm DANI POTRUS DD143X Examensarbete inom datalogi, grundnivå Handledare: Michael Schliephake Examinator: Örjan Ekeberg CSC, KTH 2015-05 1 Referat Glesa matriser är inom fokus för numeriska algoritmer som löser linjära ekvationssystem. Många lagringsmetoder har under åren tagits fram för att lagra stora glesa matriser på ett minneseffektivt och tidseffektivt sätt. I denna rapport undersöks tillgängliga lagringsmetoder för glesa ostrukturerade matriser. Formaten som undersöks och implementeras är COO, CRS och ELL formaten. Jämförelser görs på totala lagringsminnet och lagringstiden vid lagrandet av glesa matriser med olika fyllningsgrader, samt den totala beräkningstiden vid lösning med en numerisk algoritm. Resultatet visar att CRS formatet är effektivast vid lagringen av en gles matris. Slutsatsen är att det finns lagringsmetoder som lagrar en matris utan att ta upp onödigt minne och som bevarar matrisstrukturen inom rimlig tid för processen. 2 Abstract Sparse matrices are often used in numerical algorithms that solve linear equation systems. Many methods for storing sparse matrices have been proposed and implemented during the years. These methods focus primarily on minimizing the total memory consumption and the time that it takes to store a sparse matrix. This report researches the available storage methods for sparse unstructured matrices. The formats that are researched and implemented are COO, CRS and ELL. The comparisons between the formats are made based on the storage memory and time for the sparse matrices with different filling ratios. A numerical algorithm has also been implemented to study the time it takes to solve a sparse matrix with one of the available storage formats, ELL. The results show that the CRS format outperform the other formats in the storage of a sparse matrix. It is concluded that there are storage methods for sparse matrices that avoid taking up unnecessary memory space, simultaneously preserving the matrix structure and doing so within a reasonable time. 3 4 Innehåll Introduktion ............................................................................................................................................ 7 1.1 Syfte ............................................................................................................................................... 7 1.2 Studiens disposition ...................................................................................................................... 7 1.3 Frågeställning ................................................................................................................................ 7 Bakgrund ................................................................................................................................................. 9 2.1 Glesa matriser ............................................................................................................................... 9 2.2 Olika lagringsmetoder och datastrukturer .................................................................................. 10 2.2.1 Dictionary of Keys (DOK) .......................................................................................................... 11 2.2.2 List of lists (LIL) ......................................................................................................................... 11 2.2.3 Coordinate List (COO) ............................................................................................................... 12 2.2.4 Yale Sparse Matrix .................................................................................................................... 13 2.2.5 Compressed Row Storage ........................................................................................................ 13 2.2.6 Compressed Sparse Column ..................................................................................................... 14 2.2.7 ELL (Ellpack-ltpack) ................................................................................................................... 14 2.3 Gauss-Seidels metod ................................................................................................................... 15 Metod .................................................................................................................................................... 19 3.1 Jämförelse av lagringsmetoder ................................................................................................... 19 3.2 Datastrukturer ............................................................................................................................. 20 3.2.1 CRS ............................................................................................................................................ 20 3.2.2 COO .......................................................................................................................................... 20 3.2.3 ELL............................................................................................................................................. 21 3.3 Matriser ....................................................................................................................................... 21 3.4 Test miljö ..................................................................................................................................... 22 3.4.1 Hårdvara ................................................................................................................................... 22 3.4.2 Mjukvara................................................................................................................................... 22 Resultat ................................................................................................................................................. 24 4.1 Lagringstid ................................................................................................................................... 24 4.2 RAM-minne.................................................................................................................................. 27 4.3 Lösningstid med Gauss-Seidel ..................................................................................................... 30 5 4.4 Formatens effektivitet ................................................................................................................. 33 Diskussion ............................................................................................................................................. 35 5.1 Val av algoritm ............................................................................................................................. 35 5.2 Lagringsmetodernas effektivitet ................................................................................................. 35 5.2.1 Minneseffektivitet .................................................................................................................... 35 5.2.2 Tidseffektivitet.......................................................................................................................... 36 5.3 Implementeringarnas effektivitet ............................................................................................... 36 Slutsats .................................................................................................................................................. 39 6.1 Studiens slutsats .......................................................................................................................... 39 6.2 Framtida forskning ...................................................................................................................... 39 Appendix ............................................................................................................................................... 41 Appendix A: Kod för implementation av COO formatet ................................................................... 41 Appendix B: Kod för implementation av ELL formatet...................................................................... 43 Appendix C: Kod för implementation av CRS formatet ..................................................................... 45 Appendix D: Gauss Seidels metod ..................................................................................................... 48 Referenser ............................................................................................................................................. 50 6 Kapitel 1 Introduktion Glesa matriser har länge varit inom fokus för algoritmer som löser linjära ekvationssystem. En gles matris, som definieras av att den består av mer noll-element än andra element i matrisen, kan ha många olika lagringsmetoder. Att lagra en gles matris naivt såsom alla andra matriser i program har visat sig vara ineffektivt då detta tar upp onödigt minne och utför överflödiga beräkningar under algoritmens körning. Därför är det både intressant och relevant att fördjupa sig inom vilka lagringsmetoder som finns för glesa matriser för att undersöka algoritmens tidseffektivitet för olika lagringsstrukturer och hur mycket minne som sparas. 1.1 Syfte Denna studie har som syfte att undersöka olika lagringsmetoder som finns för glesa matriser, där en fördjupning har gjorts i de lagringsmetoder som har visat sig vara mest effektiva avsett på hur lång tid körningen tar och hur mycket minne som sparas för just dessa lagringsmetoder. Lagringsmetoderna har implementerats i C++ och jämförelser har gjorts mellan implementationerna för olika storlekar på kvadratiska glesa matriser, med hjälp av en numerisk algoritm. 1.2 Studiens disposition I kapitlet bakgrund beskrivs lagringsstrukturerna och hur effektiva de är för glesa matriser med olika strukturer. I metodbeskrivningen har 3 lagringsstrukturer valts ut för att implementeras i ett maskinnära programmeringsspråk, nämligen C++. Resultatdelen av denna studie visar grafer på jämförelser för hur mycket minne som sparas och hur lång tid det tar att lagra matrisen samt att beräkna det linjära ekvationssystemet Ax = b med en numerisk algoritm. I slutsatsen diskuteras de olika lagringsstrukturernas effektivitet och vilka optimeringar som kan göras. 1.3 Frågeställning Vilka lagringsmetoder är mest minneseffektiva i lagrandet av en gles matris och hur tidseffektivt blir lösningen av det linjära ekvationssystemet med en numerisk algoritm? Hur beror dessa på matrisens storlek och fyllningsgrad? 7 8 Kapitel 2 Bakgrund Detta kapitel ger en introduktion på vad glesa matriser är och hur de kan användas inom verkliga situationer. Olika lagringsmetoder tas upp samt deras för-och nackdelar. Den numeriska algoritmen som kommer att implementeras, nämligen Gauss-Seidels metod, beskrivs i detalj. 2.1 Glesa matriser Glesa matriser definieras i den numeriska analysen som matriser vars element består till största delen av nollor. Har matrisen däremot fler nollskilda element så är matrisen tät. Fyllningsgraden i en gles matris beskriver i procent hur många nollskilda element som matrisen består av. Glesheten korresponderar till system som har svaga länkar mellan varandra. Man kan tänka sig att man har n bollar som är länkade tillsammans med en fjäder från varje boll till den andra. Detta system beskrivs av en gles matris, då varje boll endast har en länk till endast en annan boll. Om varje boll istället hade varit länkad till alla andra bollar hade systemet beskrivits av en tät matris. I figur 2.1.1 visas ett exempel på en gles matris av storlek 1000x1000 med 10 % fyllningsgrad. Det vita området i grafen representerar nollor och det blåfärgade området representerar nollskilda element. 9 Figur 2.1.1: Exempel på en gles matris med 10 % fyllningsgrad. Stora glesa matriser dyker ofta upp inom vetenskapliga eller ingenjörsmässiga tillämpningar, exempel på dessa är fackverkskonstruktioner och fouriertransformer. Figur 2.1.2 beskriver en fackverkstakstol respektive ram. Denna struktur kan beskrivas med hjälp av glesa matriser. Figur 2.1.2: Fackverkskonstruktioner, som kan beskrivas av glesa matriser [1]. 2.2 Olika lagringsmetoder och datastrukturer Eftersom en gles matris element består till största delen av nollor så är det viktigt att smart lagra dessa på ett sätt som inte tar upp onödigt minne. Lagrar man matrisen direkt så kommer nollorna i matrisen att sparas i minnet och onödig minnesarea kommer att tas upp. 10 Olika lagringsmetoder har tagits fram för att lagra glesa matriser. Lagringsmetoderna har som främsta uppgift att lagra matrisens nollskilda element utan att lagra matrisens nollor men som bevarar varje elements position i matrisen indirekt. Vissa lagringsmetoder saknar potentialen att utföra elementära matrisoperationer såsom matris-vektor multiplikation. Nedan presenteras olika typer av lagringsmetoder, med unika lagringssätt. 2.2.1 Dictionary of Keys (DOK) Istället för att spara matrisens nollor kan man istället använda sig av en Dictionary of Keys, där man mappar en nyckel till ett värde. I detta fall kan man associera (rad, kolonn) till de element som är nollskilda och på så sätt få en struktur som sparar värden på ett effektivt sätt. Om gleshetens struktur på matrisen är okänd så är denna lagringsmetod effektiv för lagring [2]. Med denna implementation får man dessvärre nackdelar såsom att man inte kan iterera igenom elementen i lexikografisk ordning. Man konverterar därför matrisen till ett annat format, såsom CRS eller CSC (se 2.2.5–2.2.6), för att kunna utföra aritmetiska operationer [3]. Figur 2.2.1 är ett exempel på en gles 3x3 matris i DOK format. Matrisen innehåller rader och kolonner, där rader representeras av r och kolonner representeras av c. Enbart nollskilda element mappas på rad,kolonn som är nyckeln och det nollskilda elementet är värdet. Figur 2.2.1: Exempel på en gles 3x3 matris i DOK format. 2.2.2 List of lists (LIL) Sparar en lista per rad där varje lista innehåller kolumn index och värde. Dessa hålls sorterade på kolumn index för snabbare åtkomst av värdet [4]. 11 Denna lagringsmetod görs för konstruktion av matrisen och matrisen konverteras sedan till CRS eller CSC format för att kunna utföra matris aritmetiska operationer. Lagringsmetoden är effektiv vid t.ex. inläsning av matriser från fil [5]. I figur 2.2.2 visas ett exempel på en gles 4x5 matris i LIL format. Matrisen har rader och kolonner som beskrivs av r respektive c. LIL strukturen har en lista som innehåller listor. Listorna i listan innehåller kolonnindex för respektive nollskilt element. Varje lista i listan är sorterat efter rad och kolonnindex, för snabbare åtkomst av element i matrisen. Den första listan i listan (se höger figur i figur 2.2.2) är alltså den första raden med kolonnindex för nollskilda element och den andra listan är den andra raden med kolonnindex för nollskilda element. Figur 2.2.2: Exempel på en gles 4x5 matris i LIL format. 2.2.3 Coordinate List (COO) Sparar 3 olika listor som innehåller rad, kolonn och motsvarande nollskilda elements värde. Mest effektivt blir det om man sorterar efter rad index och sen kolonn index för att förbättra direktåtkomsttiden. Denna lagringsmetod används för konstruktion av matrisen, men kan inte användas för aritmetiska operationer, då sökningen av ett element tar linjärtid och för stora matriser tar detta för lång tid [6]. Figur 2.2.3 är ett exempel på en gles 4x4 matris i COO format. Matrisens nollskilda element sparas på radindex, kolonnindex och det nollskilda elementet, där radindex läggs i radvektorn, kolonnindex läggs i kolonnvektorn och elementet läggs i värdesvektorn. 12 Figur 2.2.3: Exempel på en gles 4x4 matris i COO format [7]. 2.2.4 Yale Sparse Matrix En matris, B, lagras i form av tre endimensionella vektorer, kallade A, IA och JA. Vektorn A innehåller alla nollskilda element i B läst från vänster till höger, uppifrån och ner. Vektorn IA är av storlek n+1 (där n är matrisstorleken) och innehåller indexet i A för det första elementet i varje rad följt av det totala antalet nollskilda element. JA innehåller kolumnpositionerna för talen i A, läst radvis från vänster till höger [8]. Figur 2.2.4 är ett exempel på en gles 4x4 matris i Yale Sparse Matrix format. Vektorn A innehåller alla nollskilda element i matrisen B. IA[i] innehåller indexet i A för det första nollskilda elementet i rad i. Rad i för matrisen förlängs från A[IA[i]] till A[IA[i+1]-1], alltså börjar den från början av en rad tills det sista indexet i raden innan den börjar på nästa rad. JA innehåller kolumnpositionerna för elementen i A. Figur 2.2.4: Exempel på en 4x4 gles matris i Yale Sparse Matrix format. 2.2.5 Compressed Row Storage Man sorterar matrisens element på rad (från toppen till botten) och kolonn (i raden – från vänster till höger). Figur 2.2.5 är ett exempel på en gles matris i CRS format. CRS formatet har en vektor för rad offsets, en vektor för kolonnindex och en vektor för att spara de nollskilda elementen i matrisen. Rad offset vektorn sparar indexet i värdesvektorn för det första nollskilda elementet 13 i varje rad och innehåller som sista element det totala antalet nollskilda element i matrisen. Kolonnindex vektorn innehåller varje nollskilt elements kolonnindex och värdesvektorn innehåller de nollskilda elementen sparade radvis från vänster till höger, uppifrån och ner. Figur 2.2.5: Exempel på en gles 4x4 matris i CRS format [7]. Oavsett om matrisen är strukturerad eller ostrukturerad så är CRS den mest effektiva på minneslagring. Det finns enstaka fall då andra lagringsmetoder är mer effektiva, men för stora glesa matriser har det visat sig att CRS tar upp minst byte per nollskilda element [9]. Den enda skillnaden mellan COO och CRS formatet är att COO har en radvektor istället för en vektor med rad offsets, vilket gör det enkelt att konvertera mellan formaten. CRS formatet är också ett effektivt format vid elementära matrisoperationer såsom matrisvektor produkt [10]. 2.2.6 Compressed Sparse Column CSC format är identiskt med CRS med undantaget att man har kolonn offsets istället för rad offsets och en vektor med rad index istället för kolonn index. 2.2.7 ELL (Ellpack-ltpack) ELL formatet sparar glesa matriser med två tvådimensionella vektorer, en för de nollskilda elementen och en för varje elements kolumn index. Detta format är mest effektivt om varje rad i matrisen har lika många nollskilda element och matrisens struktur har ett mönster som är ostrukturerat [10]. Figur 2.2.7 är ett exempel på en gles 4x4 matris i ELL format. Matrisen har som mest 3 nollskilda element i en rad och därför blir längden för varje rad i de tvådimensionella vektorerna 3. Kolonnindexet sparas i kolonnindex vektorn och om det finns ett mindre antal nollskilda element på den specifika raden än den rad som innehåller mest nollskilda element så läggs element till för att fylla ut raden. Detta kallas för utfyllning. Det nollskilda elementet 14 sparas i den tvådimensionella vektorn för värden och om raden inte är fylld så görs utfyllnings här också. Varje rad representerar alltså varje rad i matrisen. Figur 2.2.7: Exempel på en 4x4 gles matris i ELL format [7]. 2.3 Gauss-Seidels metod Gauss-Seidels metod är en iterativ metod för att lösa ett kvadratiskt linjärt ekvationssystem bestående av n stycken ekvationer med okända variabler x, Ax = b. Gauss-Seidels metod itererar, för begynnelse värden på x, tills den konvergerar mot en lösning. Metoden beskrivs av figur 2.3.1. Den okända variabeln i ekvationssystemet, xi(k+1), beräknas genom att man tar högerledet bi i ekvationen och subtraherar med summan av elementen multiplicerat med värdet för den specifika raden i, d.v.s. aij*xj(k+1) och summan av elementen multiplicerat med det föregående värdet, d.v.s aij*xj(k), dividerat med elementet på diagonalen aii. Figur 2.3.1: Gauss-Seidels metod för en nxn matris [11]. Två viktiga egenskaper med Gauss-Seidels metod bör noteras. Det ena är att varje beräkning görs i en följd. Eftersom varje komponent i den nya iterationen är beroende av de komponenter som beräknats innan så kan ingen uppdatering ske samtidigt som beräkningen görs såsom i Jacobis metod. Sedan är det så att den nya iterationen, xi(k+1), beror på ordningen som ekvationerna undersöks i. Om ordningen ändras kommer de nya iterationernas komponenter också att ändras.[12] 15 Figur 2.3.2 beskriver stop kriteriet för metoden. Normen för residual vektorn r, som är ekvivalent med att man subtraherar högerledet b med ekvationssystemet Ax(k), divideras med normen för högerledet. Detta används under beräkningen för att undersöka att felet i beräkningen ligger under en viss tolerans ε. Figur 2.3.2: Stop kriterium för Gauss-Seidels metod [11]. Gauss-Seidels metod är applicerbar på matriser som är strikt diagonalt dominerande eller symmetrisk positivt definita. Figur 2.2.3 visar ett exempel på Gauss-Seidels metod som är skriven i matlab kod. Detta exempel kommer att översättas till programmeringsspråket C++ som kommer att användas under implementationen av lagringsmetoderna. Det ska noteras att implementation av GaussSeidels metod som skrivs i C++ använder aritmetiska operationer med nollor även om den implementerade datastrukturen inte innehåller nollor i minnet. Detta kommer att användas för jämförelse under studien. 16 Figur 2.3.3: Gauss-Seidels metod skriven i MATLAB kod [13]. 17 18 Kapitel 3 Metod Detta kapitel beskriver metodiken och framtagningen av de lagringsmetoder som implementeras i språket C++. I den första delen så görs en jämförelse av lagringsmetoderna med hjälp av tidigare studier som gjorts inom området. Efter jämförelse så väljs 3 lagringsmetoder ut som kommer att implementeras. Det beskrivs sedan i detalj hur datastrukturen kommer att se ut på lagringsmetoderna och hur implementationen går till, samt i vilken miljö testning kommer att ske. 3.1 Jämförelse av lagringsmetoder En jämförelse görs på tre olika lagringsmetoder som beskrivs i kapitel 2. Dessa lagringsmetoder kommer sedan att implementeras i programmeringsspråket C++ för vidare jämförelse på minneslagring och tidseffektivitet. En av implementationerna används sedan för lösning av ett linjärt ekvationssystem Ax = b, med hjälp av Gauss-Seidels metod. Det görs också ett test med C++ bibliotekets inbyggda matris representation, en tvådimensionell vektor datastruktur. Matrisen sparas på ett naivt sätt, d.v.s. med nollor, och löses sedan med GaussSeidels metod. Datastrukturerna representeras som klasser i C++. För att kunna implementera dessa datastrukturer så har en litteraturstudie gjorts på tidigare arbeten inom samma område. Av lagringsmetoderna som beskrivs i bakgrunden så är det inte alla som har kapaciteten att utföra elementära matrisoperationer, såsom matris-vektor multiplikation. Dessa lagringsmetoder kommer inte att användas under denna studie. Exempel på dessa är LIL och DOK, som beskrivs i kapitel 2. De lagringsmetoder som har valts för implementering är CRS, COO och ELL formaten. Dessa lagringsmetoder har visat sig vara mest effektiva för glesa matriser som är ostrukturerade och av godtycklig storlek, när det gäller minneseffektivitet [9]. CRS formatet föredras vid lagrandet av glesa matriser, då det är användbart för elementära matrisoperationer. På grund av COO formatets bekvämlighet så används det ofta vid inläsning av glesa matriser, dock så konverteras formatet senare till ett annat för att kunna utföra matematiska beräkningar [14]. ELL formatet är en väldigt effektiv lagringsmetod då det gäller implementeringar av GPU datastrukturer och har valts som en kontrast till CRS formatet som är extremt effektivt för matris-vektor multiplikation [15]. 19 3.2 Datastrukturer Nedan följer datastrukturerna som kommer användas för lagring av de glesa matriserna. Dessa datastrukturer skrivs i C++. C++ har valts eftersom att det har visat sig vara extremt resursfullt när det gäller bibliotek med matrisimplementationer som innehåller matrisoperationer och vektoroperationer. Språkets bibiliotek erbjuder bl.a. vector, en lagringsstruktur som beskriver en vektor skriven i C++. Varje datastruktur implementeras och testas med glesa matriser av kvadratisk storlek. 3.2.1 CRS CRS sparar rad-offsets för antalet rader i matrisen + 1 i en vektor, alltså blir storleken på vektorn n + 1. Kolonn index för varje nollskilt element i matrisen (läst från vänster till höger, topp till botten på varje rad) sparas också i en vektor. De nollskilda elementen i matrisen sparas sedan i en vektor, där varje värde sparas i ordning från rad till rad (vektor storleken är densamma som kolonn vektorn). En klass med metoder och attribut specifika för CRS formatet skapas. Datastrukturen beskrivs genom följande: • • • En konstruktor där man anger storleken på matrisen och antalet nollskilda element. En operator() metod som stoppar in ett värde på plats i, j där i är rad och j kolonn. Denna metod stoppar in värdet i element vektorn beroende på vilket index i kolonn vektorn som specificeras. Rad offset vektorn uppdateras. En operator() metod som hämtar ett värde på plats i, j. Denna metod kommer att utnyttja rad offset vektorn. 3.2.2 COO COO sparar i en vektor indexet för raden där det nollskilda elementet finns, så storleken på vektorn blir densamma som antalet nollskilda element i den glesa matrisen. Det sparas också i en vektor indexet för kolonnen där det nollskilda elementet finns, storleken blir densamma som rad vektorn. Det kommer också att sparas en vektor som innehåller värdena för varje nollskilt element. Datastrukturen består av följande: • • En konstruktor där rad, kolonn och värdes vektorn skapas. En operator() metod som stoppar in ett värde på plats i, j där i är rad och j kolonn. Denna metod stoppar in värden i rad, kolonn samt element vektorn. 20 • En operator() metod som hämtar ett värde på plats i, j. Denna metod kommer utnyttja rad och kolonn vektorerna för att hämta värdet. 3.2.3 ELL ELL sparar i en tvådimensionell vektor indexet för kolumnen där det första nollskilda elementet finns och sedan resterande nollskilda element. Storleken på denna tvådimensionella vektor blir n*nnz, där nnz är det största antalet nollskilda element som finns på varje rad i matrisen och n är matrisstorleken. En tvådimensionell vektor av samma storlek används också för att spara de nollskilda elementen. Om en rad innehåller mindre än det största antalet nollskilda element, nnz, så kommer nollor att sparas i just den rad som sparas just nu. Det blir alltså nollor i kolumn index och nollor som värde. Detta kallas för utfyllning. Denna implementering innehåller följande: • • • En konstruktor där man anger storlek på matrisen och nnz, det största antalet nollskilda element per rad. Fyra vektorer, en tvådimensionell vektor för nollskilda element och en tvådimensionell vektor för kolonn index skapas samt en vektor för element och en vektor för kolonn index. En operator() metod som stoppar in ett värde på plats i, j där i är rad och j kolonn. Denna metod stoppar in värdet i den tvådimensionella vektorn för nollskilda element och kolumn indexet j stoppas in i den tvådimensionella vektorn för kolumn index. En operator() metod som hämtar ett värde på plats i, j. Denna metod utnyttjar de tvådimensionella vektorerna för att hämta ut det nollskilda elementet på plats i, j. 3.3 Matriser Matriserna som används för testning är ostrukturerade glesa kvadratiska matriser av storlek 1000x1000, 2500x2500, 5000x5000 och 10000x10000. Testningen kommer att göras för fyllningsgraderna 1 %, 25 %, 50 % och 75 %. Det finns 4 matriser för varje storlek, alltså 16 matriser totalt. Matriser som har en fyllningsgrad >= 50 % räknas som täta. Dessa matriser finns med i studien för att kunna undersöka lagringsmetodernas effektivitet på täta matriser jämfört med en vanlig tvådimensionell vektor i C++ som sparar alla element, även nollor. Framtagning av matriser har gjorts med hjälp av matlab. För att skapa en gles matris av storlek n används funktionen zeros [16]. Matrisen fylls sedan in kontinuerligt tills en viss fyllningsgrad nås. För att få fram en ostrukturerad matris har rand funktionen använts för att stoppa in nollskilda element i matrisen på ett slumpmässigt sätt [17]. 21 3.4 Test miljö Nedan följer specifikationer för vilken testmiljö som används under studiens arbetsgång. 3.4.1 Hårdvara CPU: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz 2.40 GHz GPU: Intel(R) HD Graphics 4400 RAM-minne: SODIMM DDR3L 8 GB @ 1600 MHz Lagring: 128 GB SSD @ 6GB/s 3.4.2 Mjukvara Operativsystemet som har använts vid testning är Windows 8.1 för 64-bit. 22 23 Kapitel 4 Resultat Detta kapitel presenterar de resultat som har fåtts fram vid lagring av de glesa matriserna med de olika datastrukturerna. Resultatet visar lagringstid och det totala använda RAM minnet vid lagringen samt den totala lösningstiden för det linjära ekvationssystemet med Gauss-Seidels metod, som presenteras med grafer och tabeller. 4.1 Lagringstid Graferna nedan visar den totala lagringstiden för matriserna med olika fyllningsgrader. Figur 4.1.1 visar den beräknade lagringstiden, för matriser av olika storlekar och med 1 % fyllningsgrad, för varje lagringsformat. Tiden är beräknad i sekunder. För matriser med 1 % fyllningsgrad så lagrar COO och CRS formaten på ungefär samma tid, dock så är ELL lite långsammare. Figur 4.1.1: Totala lagringstiden för de olika lagringsformaten. Fyllningsgrad 1 %. Figur 4.1.2 visar den beräknade lagringstiden, för matriser av olika storlekar och med 25 % fyllningsgrad, för varje lagringsformat. För matriser med 25 % fyllningsgrad så lagrar COO och ELL formaten på ungefär samma tid och CRS lagrar snabbast. Skillnaden är dock minimal. 24 Figur 4.1.2: Totala lagringstiden för de olika lagringsformaten. Fyllningsgrad 25 %. Figur 4.1.3 visar den beräknade lagringstiden, för matriser av olika storlekar och med 50 % fyllningsgrad, för varje lagringsformat. För matriser med 50 % fyllningsgrad så är den totala lagringstiden ungefär samma för alla format. Figur 4.1.3: Totala lagringstiden för de olika lagringsformaten. Fyllningsgrad 50 %. Figur 4.1.4 visar den beräknade lagringstiden, för matriser av olika storlekar och med 75 % fyllningsgrad, för varje lagringsformat. För matriser med 75 % fyllningsgrad så är lagrar COO och CRS på ungefär samma tid och ELL lagrar lite långsammare. Det ska dock noteras att bara matriser av storlek 1000-5000 lagrades under denna körning, då större matrisstorlekar inte kunde allokera nog med minne för vektorerna i CRS och COO formaten. 25 Figur 4.1.4: Totala lagringstiden för de olika lagringsformaten. Fyllningsgrad 75 %. Figur 4.1.5 visar den totala lagringstiden för de olika lagringsformaten med en konstant matrisstorlek 1000 och en varierande fyllningsgrad. Man ser att växande fyllningsgrad innebär en förbättring av ELL formatet och försämring av COO formatet. CRS lagrar på den snabbaste tiden. Figur 4.1.5: Totala lagringstiden för de olika lagringsformaten med varierande fyllningsgrad, matrisstorlek 1000. Figur 4.1.6 visar den totala lagringstiden för de olika lagringsformaten med en konstant matrisstorlek 5000 och en varierande fyllningsgrad. För denna matrisstorlek så lagrar COO långsammast och CRS på den snabbaste tiden. 26 Figur 4.1.6: Totala lagringstiden för de olika lagringsformaten med varierande fyllningsgrad, matrisstorlek 5000. 4.2 RAM-minne För att kunna mäta hur effektivt minnet lagras med de olika lagringsformaten så används glesa matriser av olika storlekar och fyllningsgrader. Figur 4.2.1 visar det totala lagringsminnet för de olika lagringsformaten med 1 % fyllningsgrad på matriserna. För matriser med 1 % fyllningsgrad så lagrar CRS det minsta antalet bytes. ELL lagrar det största antalet bytes och COO lagrar lite mindre än ELL. Figur 4.2.1: Totala lagringsminnet för de olika lagringsformaten. Fyllningsgrad 1 %. Figur 4.2.2 visar det totala lagringsminnet för de olika lagringsformaten med 25 % fyllningsgrad på matriserna. För matriser med 25 % fyllningsgrad så lagrar CRS det minsta 27 antalet bytes. ELL lagrar det största antalet bytes och COO lagrar lite mindre än ELL, dock så är skillnaden relativt liten. Figur 4.2.2: Totala lagringsminnet för de olika lagringsformaten. Fyllningsgrad 25 %. Figur 4.2.3 visar det totala lagringsminnet för de olika lagringsformaten med 50 % fyllningsgrad på matriserna. CRS lagrar fortfarande det minsta antalet bytes. COO lagrar det största antalet bytes och ELL lagrar lite mindre än COO. Ju tätare matrisen blir ju sämre blir effektiviten för COO formatet. Figur 4.2.3: Totala lagringsminnet för de olika lagringsformaten. Fyllningsgrad 50 %. Figur 4.2.4 visar det totala lagringsminnet för de olika lagringsformaten med 75 % fyllningsgrad på matriserna. CRS lagrar det minsta antalet bytes. COO lagrar det största antalet bytes och ELL lagrar lite mindre än COO. COO formatets effektivitet har blivit sämre. 28 Figur 4.2.4: Totala lagringsminnet för de olika lagringsformaten. Fyllningsgrad 75 %. Figur 4.2.5 visar det totala lagringsminnet för de olika lagringsformaten med konstant matrisstorlek 1000 och varierande fyllningsgrad. Precis som innan så dominerar CRS formatet. COO formatet blir sämre ju tätare matrisen blir, som visat i figur 2.2.4. Figur 4.2.5: Totala lagringsminnet för de olika lagringsformaten med varierande fyllningsgrad, matrisstorlek 1000. Figur 4.2.6 visar det totala lagringsminnet för de olika lagringsformaten med konstant matrisstorlek 5000 och varierande fyllningsgrad. CRS formatet lagrar effektivast. I början lagrar COO och ELL ungefär lika mycket minne, dock ju tätare matrisen blir så försämras effektiviteten för COO som påståtts innan. 29 Figur 4.2.6: Totala lagringsminnet för de olika lagringsformaten med varierande fyllningsgrad, matrisstorlek 5000. 4.3 Lösningstid med Gauss-Seidel Lösningstiden för en numerisk algoritm har beräknats med formatet ELL. Detta format har använts då det är det enda av de 3 lagringsformaten som kunde hantera en tät 10000x10000 matris, d.v.s. av fyllningsgrad >= 50 %. Lösningstiden beräknas också med en tvådimensionell vektor från C++ biblioteket för jämförelse. I dessa tvådimensionella vektorer sparas alla element, även nollor. I figur 4.3.1 visas den totala tid det tar att lösa det linjära ekvationssystemet Ax = b med Gauss-Seidels metod för matriser av olika storlekar och fyllningsgrader. Tidsskillnaden är minimal i början men ökar ju tätare matrisen blir. 30 Figur 4.3.1: Totala tiden att lösa ett linjärt ekvationssystem med Gauss-Seidel för matrisformatet ELL, olika matrisstorlekar. I figur 4.3.2 visas den totala tid det tar att lösa det linjära ekvationssystemet Ax = b med Gauss-Seidels metod för en konstant matrisstorlek 1000 med olika fyllningsgrader. Det tar längre tid att lösa en matris av större fyllningsgrad. Eftersom implementationen inte är skapad för täta matriser så är tidsskillnaden en naturlig konsekvens av detta. Figur 4.3.2: Totala tiden att lösa ett linjärt ekvationssystem med Gauss-Seidel för matrisformatet ELL, matrisstorlek 1000 med olika fyllningsgrader. I figur 4.3.3 visas den totala tid det tar att lösa det linjära ekvationssystemet Ax = b med Gauss-Seidels metod för en konstant matrisstorlek 5000 med olika fyllningsgrader. Ännu en gång tar det längre tid att lösa en matris av större fyllningsgrad. 31 Figur 4.3.3: Totala tiden att lösa ett linjärt ekvationssystem med Gauss-Seidel för matrisformatet ELL, matrisstorlek 5000 med olika fyllningsgrader. Figur 4.3.4 visar en jämförelse mellan lösningstiden för det linjära ekvationssystemet Ax = b med Gauss-Seidels metod för en konstant matrisstorlek 1000 med olika fyllningsgrader. ELL formatet har jämförts med C++ inbyggda tvådimensionella vektor implementation. Vektor implementationen har lagrat nollor i sin körning, vilket ELL formatet inte har. Eftersom Gauss-Seidels metod inte har optimerats för just denna lagringsmetod, då lagringsmetoden hämtar nollor och beräknar dessa under körningen, och ELL formatet inte är effektivt för täta matriser (fyllningsgrad >= 50%) så löser vektor implementationen på en mycket kortare tid. Figur 4.3.4: Totala tiden att lösa ett linjärt ekvationssystem med Gauss-Seidel för matrisformatet ELL samt en vanlig vektor implementation, matrisstorlek 1000 med olika fyllningsgrader. 32 4.4 Formatens effektivitet Formatens effektivitet har jämförts på hur lång tid det tar att lagra ett nollskilt element och hur mycket minne det tar. Medelvärdet har beräknats och jämförs i tabellform. Tabell 4.3.1 representerar hur minneseffektiva implementationerna har varit under lagringen. Eftersom det är nollskilda element som undersöks, och nollor inte sparas, mäts minneseffektiviteten enligt det totala använda minnet dividerat med det totala antalet nollskilda element för matrisen. Medelvärdet har beräknats för olika fyllningsgrader. CRS formatet lagrar den minsta mängden bytes per nollskilt element och är alltså mest effektiv för lagring. Lagringsformat Typ: Double COO CRS ELL 16.0 Bytes/element 12.0 Bytes/element 15.4 Bytes/element Tabell 4.3.1: Bytes per nollskilt element för varje lagringsstruktur. Tabell 4.3.2 representerar hur tidseffektiva implementationerna har varit under lagringen. Tidseffektiviten har mäts genom att ta den totala lagringstiden dividerat med antalet nollskilda element för matrisen. Medelvärdet har beräknats för olika fyllningsgrader. CRS lagrar på den minsta tiden per nollskilt element men tidsskillnaden är minimal mellan lagringsformaten. Lagringsformat Tid i mikrosekunder COO CRS ELL 3.82 µs/element 3.76 µs/element 3.80 µs/element Tabell 4.3.2: Tiden det tar att lagra ett nollskilt element för varje datastruktur. 33 34 Kapitel 5 Diskussion Detta kapitel diskuterar resultaten som tagits fram under undersökningen. Lagringsmetodernas minneslagring och lagringstid diskuteras samt deras effektivitet. Implementationernas effektivitet diskuteras och nackdelar med användandet av Gauss-Seidels metod för lösning av matrisernas linjära ekvationssystem tas fram. 5.1 Val av algoritm Gauss-Seidels metod är iterativ och konvergerar inte alltid mot något värde, vilket kan leda till att det uppstår fel inom lösningens tidsramar. För ostrukturerade matriser så ökar chansen för detta då strukturen på matrisen påverkar lösningsmetoden. Studien undersöker lagringseffektivitet på matriser som är ostrukturerade. Gauss-Seidels metod konvergerar snabbare på matriser som är diagonalt strukturerade. Om matriserna istället hade varit strukturerade på ett sådant sätt hade metoden konvergerat mot en lösning på en kortare tid. Det finns metoder tillgängliga för omstrukturering av matrisen till ett enklare format för beräkning, såsom Cholesky dekomposition [18]. ELL formatet, som användes vid undersökningen av metoden sparar inte nollor i minnet (förutom de som används vid utfyllning). Dessa nollor finns virtuellt i programmet och returneras i get metoden ifall inget annat värde hittas, detta leder till att vektorerna som bygger upp datastrukturen först undersöks och om inget hittas så returneras en nolla, vilket tar tid. Algoritmen har under studiens gång inte optimerats för någon specifik lagringsmetod utan använts rakt av enligt definitionen. Nollor beräknas under körningen med ELL formatet och effektiviteten på lagringsmetoden sjunker i detta avseende. 5.2 Lagringsmetodernas effektivitet 5.2.1 Minneseffektivitet Lagringsmetoden CRS lagrar på det mest minneseffektiva sättet, för varierande fyllningsgrader. Detta styrks i figurerna 4.2.1-4 där CRS formatet dominerar minneslagringen 35 och tar upp den minsta mängd bytes i RAM minnet för en gles eller tät matris av godtycklig storlek n. Formatet lagrar också det minsta antalet bytes per nollskilt element. COO formatet lagrar mindre än ELL formatet i figur 4.2.1-2. Efter att matrisen blir tätare, d.v.s. fyllningsgraden stiger som i figur 4.2.3-4, så verkar COO formatets effektivitet försämras och ELL formatet lagrar effektivare. Som beskrivs i bakgrunden så sparar ELL formatet nollskilda element med två tvådimensionella vektorer. Storleken på varje vektor i t.ex. den tvådimensionella kolonn vektorn bestäms av den rad som innehåller mest nollskilda element. Denna storlek är konstant för alla vektorer i den tvådimensionella vektorn. COO formatet lagrar i tre olika vektorer vars storlekar är densamma som antalet nollskilda element i matrisen. Eftersom ELL formatets vektorer inte påverkas av matrisens täthet lika mycket som COO formatet gör så försämras COO formatet och ELL formatet blir därför mer användbar för matriser med större fyllningsgrad, detta styrks i figur 4.2.5-6 där matrisstorleken är konstant men fyllningsgraden varierar i undersökningen. 5.2.2 Tidseffektivitet Det finns ingen markant skillnad i lagringstid för de olika formaten. Den största skillnaden som har observerats är den i figur 4.1.1 på ungefärligen en halv sekunds skillnad mellan ELL formatet och COO-CRS. Detta beror till största delen på strukturen av ELL formatet som använder sig av två tvådimensionella vektorer till skillnad från de andra formaten som använder sig av tre endimensionella vektorer. För en konstant matrisstorlek och varierande fyllningsgrad upptäcks heller inga större skillnader i lagringstid. I figur 4.1.5 noteras enbart att COO formatets effektivitet sjunker med en väldigt liten marginal ju tätare matrisen blir. CRS formatet, som också består av 3 endimensionella vektorer, påverkas inte av detta då rad offset vektorn inte växer lika mycket som COO formatets radvektor. 5.3 Implementeringarnas effektivitet Lagringsmetoderna som har implementerats har visat sig vara effektiva för glesa matriser av godtycklig storlek och som är ostrukturerade. Eftersom det nu inte tas upp lika mycket RAMminne av en enskild process så kan man överväga att köra flera processer samtidigt, för att kunna utnyttja effektiviten av lagringen. Lagringsmetoderna har under undersökningens gång inte hunnit optimeras. För formatet COO så tar det väldigt lång tid att plocka ut ett värde på plats i, j, eftersom att sökningen görs i linjärtid. För att kunna optimera detta så kan man istället implementera en binärsökning, som skulle kunna köras i mycket snabbare takt. Det nämns dock i bakgrunden att COO formatet är ett format som oftast konverteras till ett annat och brukar användas i allmänhet för inläsning 36 av matrisen. COO formatet används inte heller i undersökningen med Gauss-Seidels metod på grund av detta skäl. Gauss-Seidels metod har skrivits enligt definitionen för täta matriser. Implementationen har inte optimerats för lagringsmetoderna, vilket gör att onödiga beräkningar görs såsom hämtning av nollor och beräkningar med dessa. I figur 4.3.4 noteras det att ELL formatet har en sämre lösningstid än det vanliga formatet som C++ bibliotek erbjuder. Det huvudsakliga skälet till detta nämns ovan då lösningsmetoden inte har optimerats för någon specifik lagringsmetod och formatet används för lagring av glesa matriser. Problem uppstår också vid lagring av större matriser i det vanliga formatet, då programmet inte kan allokera nog med minne. Om lösningsmetoden hade optimerats för ELL formatet och enbart glesa matriser hade undersöks så hade formatet funktionerat på ett betydligt bättre sätt än det vanliga formatet. 37 38 Kapitel 6 Slutsats I detta kapitel presenteras studiens slutsats och diskussioner för framtida optimeringar av lagringsmetoderna. 6.1 Studiens slutsats I denna rapport har tre olika lagringsmetoder för glesa matriser implementerats och jämförts. Metoderna som jämfördes används för minneseffektivisering och tidseffektivisering vid lagring av glesa matriser. För att jämföra lagringsmetodernas effektivitet har glesa matriser av olika storlekar och fyllningsgrader använts vid testning. Resultatet visar att CRS formatet är det effektivaste formatet av formaten som har jämförts vid minneslagring. Dock är skillnaden på lagringstiden för de olika formaten minimal. Det implementerade ELL formatet är inte användbart vid lösning av ett linjärt ekvationssystem med Gauss-Seidels metod då metoden inte är optimerats för detta format. Det finns optimeringar att göra såsom att anpassa metoden för det specifika formatet, exempelvis genom att eliminera beräkningar med nollor. 6.2 Framtida forskning För framtida forskning bör man undersöka hur man effektivt kan kombinera olika lagringsformat för att skapa nya. Det existerar forskning kring detta där man har kombinerat exempelvis COO och ELL formatet för att skapa ett nytt format vid namnet HYB (Hybrid). HYB formatet kombinerar ELL formatets tidseffektivitet vid beräkning med glesa matriser samt COO formatets flexibilitet [9]. HEC är ett annat hybrid format som också är framtaget genom en kombination tidigare existerande format, ELL och CSR [19]. Det ska dock noteras att dessa format är framtagna för att effektivisera matris-vektor operationer för en grafikprocessor (GPU). 39 40 Appendix Appendix A: Kod för implementation av COO formatet Detta är en implementation av COO formatet skrivet I programmeringsspråket C++. class MatrixCOO{ public: vector <int> rowArray; vector <int> colArray; vector <double> elemArray; MatrixCOO(){}; double get(int i, int j) const{ for(int ri = 0; ri < rowArray.size(); ri++){ for(int ci = 0; ci < colArray.size(); ci++){ if(rowArray[ri] == i && colArray[ci] == j && ri == ci){ return elemArray[ri]; } } } return 0; } double& operator() (int i, int j){ rowArray.push_back(i); colArray.push_back(j); elemArray.push_back(0); return elemArray[elemArray.size() - 1]; } double amountOfBytes(){ double fullAmount; fullAmount = (rowArray.size()*4) + (colArray.size()*4) + (elemArray.size()*8); return fullAmount; } }; 41 42 Appendix B: Kod för implementation av ELL formatet Detta är en implementation av ELL formatet skrivet I programmeringsspråket C++. class MatrixELL{ public: int rowIndexSaver = 0; int sizeOfMatrix; int mostNNZ; vector<int> tempVecCol; vector<vector<int>> colArr; vector<vector<double>> valArr; vector<double> tempVecVal; MatrixELL(int sizeOfMat, int moostNNZ){ mostNNZ = moostNNZ; sizeOfMatrix = sizeOfMat; }; double get(int i, int j) const{ for(int ci = 0; ci < mostNNZ; ci++){ if(colArr[i][ci] == j){ return valArr[i][ci]; } } return 0; } double& operator() (int i, int j){ if(rowIndexSaver == i){ tempVecCol.push_back(j); tempVecVal.push_back(0); return tempVecVal[tempVecVal.size() - 1]; } else if(i > rowIndexSaver){ if(tempVecVal.size() < mostNNZ){ int q = mostNNZ tempVecVal.size(); for(int i = 0; i < q; i++){ tempVecVal.push_back(0); tempVecCol.push_back(0); } colArr.push_back(tempVecCol); 43 valArr.push_back(tempVecVal); tempVecCol.clear(); tempVecVal.clear(); rowIndexSaver++; tempVecCol.push_back(j); tempVecVal.push_back(0); return tempVecVal[tempVecVal.size() - 1]; } colArr.push_back(tempVecCol); valArr.push_back(tempVecVal); tempVecCol.clear(); tempVecVal.clear(); rowIndexSaver++; tempVecCol.push_back(j); tempVecVal.push_back(0); return tempVecVal[tempVecVal.size() - 1]; } } void lastcheck(){ if(tempVecVal.size() < mostNNZ){ int q = mostNNZ - tempVecVal.size(); for(int i = 0; i < q; i++){ tempVecVal.push_back(0); tempVecCol.push_back(0); } valArr.push_back(tempVecVal); colArr.push_back(tempVecCol); } else{ valArr.push_back(tempVecVal); colArr.push_back(tempVecCol); } } double amountOfBytes(){ return (colArr.size()*tempVecCol.size()*4) + (valArr.size()*tempVecVal.size()*8); } }; 44 Appendix C: Kod för implementation av CRS formatet Detta är en implementation av CRS formatet skrivet I programmeringsspråket C++. class MatrixCSR{ public: int offsetcounter = 0; int indexSaver; int nnz; int sizeOfMatrix; vector <int> offsetArray; vector <int> colArray; vector <double> elemArray; MatrixCSR(int sizeOfMat, int numberofNonZero){ nnz = numberofNonZero; sizeOfMatrix = sizeOfMat; }; double get(int i, int j) const{ for(int ri = 1; ri < offsetArray.size(); ri++){ if(i == ri && colArray[offsetArray[i]] == j){ return elemArray[offsetArray[i]]; } else if(i == ri && colArray[offsetArray[i-1]] != j){ int currentInd = offsetArray[i]; for(int q = i; q < sizeOfMatrix; q++){ if(colArray[currentInd + 1] == j){ return elemArray[currentInd + 1]; } currentInd++; } } } if((i) == sizeOfMatrix && (j) == sizeOfMatrix){ return elemArray[nnz-1]; } return 0; } double& operator() (int i, int j){ colArray.push_back(j); elemArray.push_back(0); if (offsetArray.size() == 0){ offsetArray.push_back(0); offsetArray.push_back(offsetcounter); indexSaver = i; return elemArray[elemArray.size() - 1]; 45 } offsetcounter++; if(elemArray.size() == nnz){ offsetArray.push_back(nnz); } else if(i > indexSaver){ offsetArray.push_back(offsetcounter); indexSaver = i; } return elemArray[elemArray.size() - 1]; } double amountOfBytes(){ return (offsetArray.size()*4 + colArray.size()*4 + elemArray.size()*8); } }; 46 47 Appendix D: Gauss Seidels metod Detta är en implementation av Gauss-Seidels metod skrivet I programmeringsspråket C++. void GaussSeidel(MatrixCSR A, int sizeofMatrix, int numOfIter, double rightSide[], double initGuess[], double saveVal[]){ while(numOfIter > 0) { for(int i = 0; i < sizeofMatrix; i++){ saveVal[i] = (rightSide[i] / A.get(i+1,i+1)); for(int j = 0; j < sizeofMatrix; j++){ if(j == i) continue; saveVal[i] = saveVal[i] - ((A.get(i+1,j+1)/A.get(i+1,i+1)) * initGuess[j]); initGuess[i] = saveVal[i]; } printf("x%d = %f ", i + 1, saveVal[i]); } cout << "\n"; numOfIter--; } } 48 49 Referenser [1] Lueger, O. (1904). Lexikon der gesamten Technik. 2nd ed. Deutsche Verlags-Anstalt. URL: http://www.zeno.org/Lueger-1904/0/Suche?o=i [Hämtades 8 Maj 2015] [2] Scipy-lectures.github.io, (2008). 2.5.2.2.3. Dictionary of Keys Format (DOK) — Scipy lecture notes. URL: https://scipy-lectures.github.io/advanced/scipy_sparse/dok_matrix.html [Hämtades 8 Maj 2015] [3] Docs.scipy.org, (2008). scipy.sparse.dok_matrix — SciPy v0.15.1 Reference Guide. URL: http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.dok_matrix.html [Hämtades 8 Maj 2015] [4] Docs.scipy.org, (2008). scipy.sparse.lil_matrix — SciPy v0.15.1 Reference Guide. URL: http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.lil_matrix.html [Hämtades 8 Maj 2015] [5] Scipy-lectures.github.io, (2008). 2.5.2.2.2. List of Lists Format (LIL) — Scipy lecture notes. URL: https://scipy-lectures.github.io/advanced/scipy_sparse/lil_matrix.html [Hämtades 8 Maj 2015] [6] Stanimirovic, I. and Tasic, M. (2009). PERFORMANCE COMPARISON OF STORAGE FORMATS FOR SPARSE MATRICES. 1st ed. FACTA UNIVERSITATIS, s.2-3. URL: http://facta.junis.ni.ac.rs/mai/mai24/fumi-24_39_51.pdf [Hämtades 8 Maj 2015] [7] Golub, Gene H.; Van Loan, Charles F. (1996). Matrix Computations (3rd ed.), Baltimore: Johns Hopkins, s.510. URL: http://web.mit.edu/ehliu/Public/sclark/Golub%20G.H.,%20Van%20Loan%20C.F.%20Matrix%20Computations.pdf [Hämtades 8 Maj 2015] [8] Eisenstat, S., Gursky, M., Schultz, M. och Sherman, A. (odaterat). Yale Sparse Matrix Package. 1st ed. Yale, s.3-4. URL: http://cpsc.yale.edu/sites/default/files/files/tr112.pdf [Hämtades 8 Maj 2015] [9] Bell, N. och Garland, M. (2009). Implementing Sparse Matrix-Vector Multiplication on ThroughputOriented Processors. 1st ed. NVIDIA, s.4, 10. URL: http://www.nvidia.com/docs/IO/77944/sc09-spmvthroughput.pdf [Hämtades 8 Maj 2015] [10] Bell, N. and Garland, M. (2008). Efficient Sparse Matrix-Vector Multiplication on CUDA. 1st ed. NVIDIA, s.6-7. URL: http://sbel.wisc.edu/Courses/ME964/Literature/techReportGarlandBell.pdf [Hämtades 8 Maj 2015] [11] Bell, N. (2011). Sparse Matrix Representations & Iterative Solvers. 1st ed. NVIDIA, s.10-12. URL: http://www.bu.edu/pasi/files/2011/01/NathanBell1-10-1000.pdf [Hämtades 8 Maj 2015] [12] Kahan, W. (1958). Gauss-Seidel Methods of Solving Large Systems of Linear Equations. Ph.D. University of Toronto [Hämtades 8 Maj 2015] 50 [13] Saadeh, M. (2011). Gauss Seidel Method for a system of equations. URL: http://www.mathworks.com/matlabcentral/fileexchange/32051-gauss-seidelmethod/content/Gauss_Seidel.m [Hämtades 8 Maj 2015] [14] Saad, Y. (2003). Iterative Methods for Sparse Linear Systems. 2nd ed. Society for Industrial and Applied Mathematics, s.113. URL: http://www-users.cs.umn.edu/~saad/IterMethBook_2ndEd.pdf [Hämtades 8 Maj 2015] [15] Antz, H., Tomov, S. och Dongarra, J. (2014). Implementing a Sparse Matrix Vector Product for the SELL-C/SELL-C-σ formats on NVIDIA GPUs. 1st ed. University of Tennessee, Knoxville, USA: Innovative Computing Lab, s.1 och s.3. URL: http://www.icl.utk.edu/sites/icl/files/publications/2014/icl-utk-7722014.pdf [Hämtades 8 Maj 2015] [16] Se.mathworks.com, (2006). Create array of all zeros - MATLAB zeros. URL: http://se.mathworks.com/help/matlab/ref/zeros.html [Hämtades 8 Maj 2015] [17] Se.mathworks.com, (2006). Uniformly distributed random numbers - MATLAB rand. URL: http://se.mathworks.com/help/matlab/ref/rand.html [Hämtades 8 MaJ 2015] [18] Zubair, M. och Ghose, M. (1992). A PERFORMANCE STUDY OF SPARSE CHOLESKY FACTORIZATION ON INTEL iPSC/860. 1st ed. Institute for Computer Applications in Science and Engineering, s.8. URL: http://www.dtic.mil/dtic/tr/fulltext/u2/a251186.pdf [Hämtades 8 Maj 2015]. [19] Liu, H., Yu, S., Chen, Z., Hsieh, B. and Shao, L. (2012). SPARSE MATRIX-VECTOR MULTIPLICATION ON NVIDIA GPU. 1st ed. Institute for Scientific Computing and Information, s.6. URL: http://www.math.ualberta.ca/ijnamb/Volume-3-2012/No-2-12/2012-02-04.pdf [Hämtades 8 Maj 2015]. 51