164
Moderne Expression Templates Programmierung Weiterentwickelte Techniken und deren Einsatz zur L¨ osung partieller Differentialgleichungen Der Technischen Fakult¨ at der Universit¨ at Erlangen-N¨ urnberg zur Erlangung des Grades DOKTOR–INGENIEUR vorgelegt von Dipl.-Math. Jochen H¨ ardtlein Erlangen — 2007

Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

Embed Size (px)

Citation preview

Page 1: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

Moderne Expression Templates Programmierung

Weiterentwickelte Techniken und

deren Einsatz zur Losung partieller

Differentialgleichungen

Der Technischen Fakultat der

Universitat Erlangen-Nurnberg

zur Erlangung des Grades

DOKTOR–INGENIEUR

vorgelegt von

Dipl.-Math. Jochen Hardtlein

Erlangen — 2007

Page 2: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

Als Dissertation genehmigt von

der Technischen Fakultat der

Universitat Erlangen-Nurnberg

Tag der Einreichung 20. Marz 2007

Tag der Promotion: 03. August 2007

Dekan: Prof. Dr. A. Leipertz

Berichterstatter: Prof. Dr. C. Pflaum

Prof. Dr. J. Wolff von Gudenberg

Page 3: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

DANKSAGUNG

Danksagung

Mein besonderer Dank richtet sich an meinen Betreuer Prof. Dr. Christoph Pflaum (Lehrstuhl Infor-

matik 10, Universitat Erlangen-Nurnberg). Im Rahmen des vorgegebenen Themengebiets gab er mir

die Moglichkeiten meine eigenen Ideen und Forschungsinteressen umzusetzen. Dabei bot er mir immer

hervorragende wissenschaftliche Hilfe und zielgerichtete Unterstutzung an, die mir oft neue Sichtweisen

und Losungsansatze eroffneten. Ich bedanke mich ganz herzlich bei Dir fur die stets freundliche Betreu-

ung, die Ehrlichkeit, alles Lob und jede Kritik! Des Weiteren mochte ich auch Prof. Dr. Jurgen Wolff

von Gudenberg (Lehrstuhl Informatik 2, Universitat Wurzburg) fur die Begutachtung dieser Arbeit

Dank sagen.

Ich bedanke mich bei der Deutschen Forschungsgemeinschaft (DFG) fur die Finanzierung meiner Stel-

le im Rahmen des DFG-Projekts Expression Templates fur partielle Differentialgleichungen (Geschaftz.

PF 372/3-1, PF 372/3-2). Dies ermoglichte mir die umfangreiche und konzentrierte Forschungsarbeit,

die zu dieser Dissertation fuhrte.

Ein herzliches Dankeschon allen derzeitigen und ehemaligen Mitarbeitern am LSS fur die freund-

schaftliche und hilfsbereite Arbeitsatmosphare in den letzten Jahren, besonders an meine Zimmergenos-

sen: Britta Heubeck, Tobias Gradl, Matthias Hummer und Markus Kowarschik. Die Zusammenarbeit

sowie die vielen fachlichen und personlichen Gesprache habe ich wirklich sehr genossen! Bei Proble-

men jeder Art bin ich auf offene Ohren und nutzliche Ratschlage gestoßen. Zusatzlich mochte ich all

diejenigen besonders herausheben, die dankenswerterweise Teile dieser Arbeit korrekturgelesen haben.

Zuletzt gilt mein tiefer Dank meiner Freundin, meiner Familie und meinen Freunden. Danke fur Eure

Geduld und die unschatzbare Unterstutzung, besonders Dir, liebe Merle!

Jochen Hardtlein

iii

Page 4: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

DANKSAGUNG

iv

Page 5: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

INHALTSVERZEICHNIS

Inhaltsverzeichnis

Abbildungs- und Tabellenverzeichnis ix

Verzeichnis der Listings xii

1 Einleitung 1

1.1 Inhaltliche Ausrichtung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2.1 Entwicklung numerischer Software . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2.2 Effiziente Implementierungen via ET . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.2.3 ET zur Losung partieller Differentialgleichungen . . . . . . . . . . . . . . . . . . 3

1.2.4 Weiterfuhrende ET-Techniken und Anwendungen . . . . . . . . . . . . . . . . . . 3

1.3 Uberblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

I ET – Grundlagen, Entstehung und Analyse 5

2 Sprachgrundlagen und Programmierkonzepte 7

2.1 Domain-specific Embedded Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2 Benutzerfreundliche, mathematische Schnittstellen . . . . . . . . . . . . . . . . . . . . . 7

2.2.1 Uberladen von Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.2.2 Benutzerdefinierte Konvertierungsoperatoren . . . . . . . . . . . . . . . . . . . . 9

2.3 Templates in C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.3.1 Definition von templatisierten Klassen und Funktionen . . . . . . . . . . . . . . . 10

2.3.2 Template-Instantiierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.3.3 Meta-Template-Programmierung . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.3.4 Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.3.5 Templategesteuerte Vererbung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.3.6 CRTP (Curiously Recurring Template Pattern) . . . . . . . . . . . . . . . . . . . 13

2.4 Optimierungen von C++-Compilern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.4.1 Elimination temporarer Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.4.2 Inlining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.4.3 Aliasing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.4.4 Optimierung von Schleifen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.4.5 Kai C++-Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.5 Zugrundeliegende Programmcodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3 Klassische ET 19

3.1 Das traditionelle Uberladen von Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.1.1 Unmittelbare Auswertung im Operator . . . . . . . . . . . . . . . . . . . . . . . 19

3.1.2 Ausdrucksbaume mittels abstrakter Klassen . . . . . . . . . . . . . . . . . . . . . 20

3.2 Klassische ET-Implementierungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.2.1 ET-Programmierung via Veldhuizen . . . . . . . . . . . . . . . . . . . . . . . . . 22

3.2.2 Verbreitete ET-Implementierungen . . . . . . . . . . . . . . . . . . . . . . . . . . 22

v

Page 6: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

INHALTSVERZEICHNIS

3.3 Bekannte ET Bibliotheken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4 Analyse von ET und Verbesserungsansatze 27

4.1 Effizienz der ET-Technik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4.2 Komponenten von ET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

4.2.1 Wrapper-Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

4.2.2 Grunddatenstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

4.2.3 Operationsklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

4.2.4 Creator Funktionen und Uberladene Operatoren . . . . . . . . . . . . . . . . . . 34

4.3 Lebensdauer von ET-Objekten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

II Weiterfuhrende Programmierung von Expression Templates 37

5 Einfache ET-Implementierung 39

5.1 Komplexitat der Implementierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

5.2 Namespace-gekapselte ET-Implementierungen . . . . . . . . . . . . . . . . . . . . . . . . 39

5.3 Einfache, typsichere ET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

5.4 Einfache ET fur temporare Ausdrucke . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

6 Fast Expression Templates 45

6.1 ET im Hochleistungsrechnen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

6.1.1 Aliasing-Probleme bei ET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

6.2 Fast Expression Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

6.2.1 Template-Nummerierung der Vektorklassen . . . . . . . . . . . . . . . . . . . . . 46

6.2.2 Meta-FET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

6.3 Leistungsanalyse der FET-Implementierungen . . . . . . . . . . . . . . . . . . . . . . . . 49

6.3.1 Allgemeine Bemerkungen zur Analyse . . . . . . . . . . . . . . . . . . . . . . . . 49

6.3.2 Effizienz auf Workstations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

6.3.3 FET auf Hochleistungsrechnern . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

6.4 Praktische Anwendung von FET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

6.4.1 Einschrankung auf rechenintensive Programmteile . . . . . . . . . . . . . . . . . 53

6.4.2 Automatisches Nummerieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

7 Erweiterte Methoden 57

7.1 Typ-Minimierung durch Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

7.2 ET fur verschiedene Datenstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

7.3 Speicherung von ET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

7.3.1 Typkapselung und Formeln-Schablonen . . . . . . . . . . . . . . . . . . . . . . . 60

7.3.2 Abspeicherung mittels abstrakter Klassen . . . . . . . . . . . . . . . . . . . . . . 61

7.4 Sichere Matrix-Multiplikationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

8 Kompilierzeiten von ET 65

8.1 Ubersetzung von ET-Programmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

8.2 Praktische Methoden zur schnelleren Compilierung . . . . . . . . . . . . . . . . . . . . . 66

8.2.1 Template-Anordnung in den Operationsklassen . . . . . . . . . . . . . . . . . . . 67

8.2.2 Balancierung der Ausdrucksbaume . . . . . . . . . . . . . . . . . . . . . . . . . . 68

8.2.3 Auslagerung von ET-Ausdrucken . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

vi

Page 7: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

INHALTSVERZEICHNIS

9 ET – Ausblick 71

9.1 Limitierungen von ET-Bibliotheken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

9.1.1 Komplexe Fehlermeldungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

9.1.2 Testbarkeit von ET-Programmen . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

9.1.3 Grenzen der Optimierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

9.2 Erweiterte Anwendungsgebiete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

9.3 Abschließende Bemerkungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

III Einsatz von ET zum Losen von partiellen Differentialgleichungen 75

10 Finite Elemente 77

10.1 Die Finite Elemente Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

10.1.1 Die schwache Formulierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

10.1.2 Gebietszerlegungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

10.1.3 Finite Elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

10.1.4 Referenzelemente und Transformationen . . . . . . . . . . . . . . . . . . . . . . . 81

10.1.5 Numerische Quadratur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

10.2 Einige Finite Elemente Approximationen . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

10.2.1 Konforme Finite Elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

10.2.2 Nichtkonforme Finite Elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

10.2.3 Gemischte FEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

10.2.4 Vektorwertige Finite Elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

10.3 FE-Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

11 Colsamm 89

11.1 Grundidee und Programmstruktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

11.1.1 Programmablauf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

11.2 Assemblierung von Diskretisierungsmatrizen . . . . . . . . . . . . . . . . . . . . . . . . . 91

11.3 Integranden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

11.3.1 Platzhalter fur Basisfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

11.3.2 Differentialoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

11.3.3 Konstanten, Polynome, Vektoren . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

11.3.4 Benutzerdefinierte, veranderliche Funktionen . . . . . . . . . . . . . . . . . . . . 95

11.4 Definition neuer Finiter Elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

11.4.1 Transformationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

11.4.2 Basisfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

11.5 Anwendungsbeispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

11.5.1 Finite Elemente im optischen Fluss . . . . . . . . . . . . . . . . . . . . . . . . . . 98

11.5.2 Quell-Lokalisation in Dipolmodellen . . . . . . . . . . . . . . . . . . . . . . . . . 100

11.6 Entwicklung und Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

11.6.1 Schnelle Berechnungen der lokalen Steifigkeitsmatrizen . . . . . . . . . . . . . . . 103

11.6.2 Erweiterungen und Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

12 Weitere Einsatzgebiete von ET 107

12.1 Mengenalgebren mittels ET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

12.2 Iterationsschleifen mittels ET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

12.3 ET-Schleifenblocking mit nummerierten Variablen . . . . . . . . . . . . . . . . . . . . . 114

vii

Page 8: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

INHALTSVERZEICHNIS

13 Abschließende Bemerkungen 117

13.1 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

13.1.1 Einfache und Leistungsstarke ET-Implementierungen . . . . . . . . . . . . . . . . 117

13.1.2 ET zum Losen von partiellen Differentialgleichungen . . . . . . . . . . . . . . . . 117

13.2 Weitere Entwicklungen und Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

IV Anhang 121

A ET-Implementierung nach Veldhuizen 123

B Colsamm – Programmstruktur 127

B.1 Template-Bibliotheken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

B.2 Programmstruktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

B.2.1 Domain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

B.2.2 Gaussian Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

B.2.3 Basis Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

B.2.4 Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

B.2.5 CornerClasses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

B.2.6 StencilTypeInit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

B.2.7 Simple Element, Mixed Element, Vectorial Element . . . . . . . . . . . . . . . . . . . . . . 132

C Programmierung von Typlisten 135

D Verwendete Computer-Plattformen 139

D.1 Arbeitsplatzrechner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

D.1.1 Pentium 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

D.1.2 Dual-Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

D.2 Hochleistungsrechner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

D.2.1 NEC SX-6/48M6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

D.2.2 Hitachi SR8000-F1/168 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

D.2.3 Cluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

E Curriculum Vitae 141

Eigene Veroffentlichungen 143

Literaturverzeichnis 145

viii

Page 9: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ABBILDUNGS- UND TABELLENVERZEICHNIS

Abbildungs- und Tabellenverzeichnis

4.1 Graphische Darstellung des ET-Ausdrucksbaums der Vektortriade. . . . . . . . . . . . . 29

6.1 Performance-Analyse der FET-Implementierungen auf Workstations. . . . . . . . . . . . 50

6.2 Laufzeitleistung von FET-Programmen auf der NEC-SX6. . . . . . . . . . . . . . . . . . 51

6.3 Untersuchung praxisbezogener FET-Anwendungen auf NEC-SX6. . . . . . . . . . . . . . 52

6.4 Performance-Vergleiche von FET-Bibliotheken unter Verwendung von OpenMP. . . . . . 53

7.1 Typkombinationen von reell- bzw. komplexwertigen Vektoren . . . . . . . . . . . . . . . 57

7.2 Untersuchung verschiedener Implementierungen zur Speicherung von ET-Objekten. . . . 63

8.1 Ubersetzungszeiten verschiedener ET-Implementierungen. . . . . . . . . . . . . . . . . . 66

10.1 Transformation des Referenzelements auf allgemeine Dreiecke. . . . . . . . . . . . . . . . 82

10.2 Abbildung einer Richtung im Referenzelement in bel. Elemente. . . . . . . . . . . . . . . 83

10.3 Transformation des Referenzelement auf isoparametrische Dreiecke mit einer krummli-

nigen Kante. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

10.4 Kantenelemente fur Dreiecke und Tetraeder. . . . . . . . . . . . . . . . . . . . . . . . . . 86

11.1 Strukturelle Darstellung der numerischen Losung von PDGen mit der Finiten Elemente

Methode unter Verwendung von Colsamm. . . . . . . . . . . . . . . . . . . . . . . . . . . 90

11.2 Programmablauf von Colsamm zur Berechnung der lokalen Diskretisierungsmatrizen. . . 91

11.3 Frames 8 und 9 der bekannten Yosemite-Sequenz. . . . . . . . . . . . . . . . . . . . . . . 99

11.4 Optisches Flussfeld fur Frame 8 und 9 der Yosemite-Sequenz. . . . . . . . . . . . . . . . 100

11.5 Visualisierung der Norm des berechneten Geschwindigkeitsfeld einer Sequenz von Herz-

bewegungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

11.6 Colsamm-Anwendung zur Berechnung von Dipolquellen in realistischen Kopfmodellen. . 103

12.1 Performance-Analyse des ET-Schleifen-Blockings. . . . . . . . . . . . . . . . . . . . . . . 116

B.1 Klassenhierarchie von Colsamm. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

ix

Page 10: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ABBILDUNGS- UND TABELLENVERZEICHNIS

x

Page 11: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

VERZEICHNIS DER LISTINGS

Verzeichnis der Listings

2.1 Vektordatenstruktur, Code-Grundlage fur weitere Implementierungen. . . . . . . . . . . 18

3.1 Implementierung eines Ausdrucksbaumes mittels abstrakter Klassen. . . . . . . . . . . . 21

3.2 Gangige Implementierungsvariante der ET-Technik. . . . . . . . . . . . . . . . . . . . . 23

3.3 Variante eines uberladenen Operators ohne explizite Wrapper-Klasse. . . . . . . . . . . . 24

4.1 Methode zum Abspeichern der Operanden ohne Wrapper. . . . . . . . . . . . . . . . . . 29

4.2 Wrapper-Klasse mit explizitem Konvertierungsoperator. . . . . . . . . . . . . . . . . . . 30

4.3 ET-Programmiervariante mit allgemeinen Operationsklassen. . . . . . . . . . . . . . . . 33

4.4 ET-Programmcode mit separaten Operationsklassen. . . . . . . . . . . . . . . . . . . . . 34

4.5 Ableitung der Operationsklassen vom Wrapper mittels CRTP. . . . . . . . . . . . . . . . 34

4.6 Vektor-Exponentialfunktion mit Creator-Funktion. . . . . . . . . . . . . . . . . . . . . . 34

5.1 Namespace-gekapselte ET-Implementierung. . . . . . . . . . . . . . . . . . . . . . . . . . 40

5.2 Programm-Code einer einfachen ET-Variante. . . . . . . . . . . . . . . . . . . . . . . . . 42

5.3 ET-Implementierung zur Speicherung temporarer Operanden. . . . . . . . . . . . . . . . 43

6.1 Template-nummerierte Vektordatenstruktur. . . . . . . . . . . . . . . . . . . . . . . . . . 47

6.2 Meta-FET-Implementierung ohne Abspeicherung der Operanden. . . . . . . . . . . . . . 48

6.3 Nummerierbare Klasse zur FET-Kapselung von Skalaren. . . . . . . . . . . . . . . . . . 48

6.4 Template-nummerierte Vektordatenstruktur zur eingeschrankten Verwendung in rechen-

intensiven Programmteilen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

6.5 Praktische Anwendung der FET-Implementierungen an rechenintensiven Stellen. . . . . 54

7.1 Traits fur die Bestimmung des Ruckgabetyps. . . . . . . . . . . . . . . . . . . . . . . . . 57

7.2 ET-Implementierung fur ubersetzergenerierte Ruckgabetypen. . . . . . . . . . . . . . . . 58

7.3 ET fur verzogerte Auswertungen der Komponentenoperationen. . . . . . . . . . . . . . . 59

7.4 Programmiervariante zum Behandeln mehrerer Datenstrukturen und Laufzeitfehlermel-

dungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

7.5 Speicherung von ET als Member-Variablen mit vollem Datentyp. . . . . . . . . . . . . . 61

7.6 Anwendung von gespeicherten FET-Ausdrucken. . . . . . . . . . . . . . . . . . . . . . . 61

7.7 Abspeicherung von ET-Objekten mittels abstrakter Klassen. . . . . . . . . . . . . . . . 62

7.8 Abspeicherung mit abstrakten Klassen und mehreren Ergebnistypen. . . . . . . . . . . . 63

8.1 Programmcodes mit vertauschten Template-Parametern. . . . . . . . . . . . . . . . . . . 68

8.2 Einfache, schneller ubersetzbare ET-Implementierung. . . . . . . . . . . . . . . . . . . . 68

11.1 Beispiel-Programm zur Anwendung von Colsamm . . . . . . . . . . . . . . . . . . . . . . 93

11.2 Implementierung der Tetraeder-Transformationsformel. . . . . . . . . . . . . . . . . . . . 96

11.3 Transformationsformel fur FE-Dreiecke mit einer krummlinigen Seite. . . . . . . . . . . 96

11.4 Definition eines Tetraederelements in Colsamm. . . . . . . . . . . . . . . . . . . . . . . . 96

11.5 Definition von Nedelec-Elementen erster Ordnung in Colsamm. . . . . . . . . . . . . . . 97

12.1 ET-Implementierung der Test- und Verknupfungsklassen zur Realisierung einer Men-

genalgebra. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

12.2 Verwendung der ET-Mengenalgebra im Anwendercode. . . . . . . . . . . . . . . . . . . . 108

12.3 Datenstruktur fur die verzogerte Auswertung in Iterationsschleifen. . . . . . . . . . . . . 109

12.4 Zusweisungsoperator zur Durchfuhrung der verzogerten Auswertung. . . . . . . . . . . . 109

12.5 Wrapper-Klasse fur Index-Ausdrucke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

12.6 ET-Programmierung der Schleifeninitialisierung. . . . . . . . . . . . . . . . . . . . . . . 110

xi

Page 12: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

VERZEICHNIS DER LISTINGS

12.7 ET-Code zur Durchfuhrung von Bedingungsabfragen. . . . . . . . . . . . . . . . . . . . 110

12.8 ET-Implementierung fur die Durchfuhrung von Iterationsschritten. . . . . . . . . . . . . 111

12.9 Index-Klasse fur die Schleifeniteration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

12.10Wrapper-Klasse der ET-Iterationsschleifen. . . . . . . . . . . . . . . . . . . . . . . . . . 112

12.11 ET-Iterationsschleife zur Durchfuhrung einfacher Iterationen. . . . . . . . . . . . . . . . 112

12.12 Anwendungsbeispiel der ET-Schleifen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

12.13 ET-Programmierung von geschachtelten Schleifen. . . . . . . . . . . . . . . . . . . . . . 113

12.14 ET-Klasse zur Kapselung der inneren Schleifen. . . . . . . . . . . . . . . . . . . . . . . 113

12.15 Geschachtelte Anwendung der ET-Schleifen. . . . . . . . . . . . . . . . . . . . . . . . . 114

12.16 Typlist-Definition in der Additionsklasse. . . . . . . . . . . . . . . . . . . . . . . . . . . 114

12.17 Erweiterung der Vektorklasse zur Durchfuhrung des Blockings. . . . . . . . . . . . . . . 115

12.18 Erweiterung der Evaluate-Klasse fur Schleifenblocking. . . . . . . . . . . . . . . . . . . . 115

12.19 ET-Iterationsschleife zur Durchfuhrung des Blockings. . . . . . . . . . . . . . . . . . . . 115

12.20 Anwendercode des geblockten Gauß-Seidel-Losers. . . . . . . . . . . . . . . . . . . . . . 116

A.1 Vektor-Klasse der ET-Implementierung nach Veldhuizen. . . . . . . . . . . . . . . . . . . 123

A.2 Funktion zur Auswertung und Zuweisung von ET-Objekten. . . . . . . . . . . . . . . . . 124

A.3 Operationsklassen und Operatoren der ursprunglichen ET-Variante . . . . . . . . . . . . 125

B.1 Liste der Template-Parameter der Klasse Domain . . . . . . . . . . . . . . . . . . . . . . 128

xii

Page 13: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ZUSAMMENFASSUNG

Zusammenfassung

Die Implementierungstechnik der Expression Templates (ET) stellt in C++ eine machtige und inter-

essante Methode dar, das benutzerfreundliche Uberladen von Operatoren mit einer effizienten Program-

mierung zu verbinden. Dabei werden mathematische Ausdrucke mittels der entsprechenden uberlade-

nen Operatoren in Template-Operationsklassen gekapselt, die hochoptimierte Berechnungen der Ergeb-

nisse in einem Auswertungsschritt erlauben. Darauf aufbauend wurden einige sehr leistungsfahige und

intuitiv anwendbare Bibliotheken, vorwiegend fur Problemstellungen der linearen Algebra, entwickelt.

Daruber hinaus sind aber auch Programmpakete zur Losung partieller Differentialgleichungen entstan-

den. Trotz der leistungsfahigen Programmierung von mathematischen Operatoren mittels ET und der

dadurch eroffneten Moglichkeit Bibliotheken mit effizienten und benutzerfreundlichen Schnittstellen zu

implementieren, fand die ET-Technik nur zogerlich Anwendung. Dies liegt einerseits an der teilweise

langwierigen und fehleranfalligen Implementierung, sowie andererseits daran, dass die ET-Programme

nicht immer die erwartete Performance erreichen. Dies zeigt sich besonders auf Hoch- und Hochst-

leistungsrechnern, wodurch die Anwendung von ET auf diesen Plattformen bis jetzt wenig Beachtung

fand.

Die vorliegende Arbeit prasentiert grundsatzliche Weiterentwicklungen der ET-Technik sowie deren

Anwendungen in Template-Bibliotheken. Dabei werden nach eingehender Analyse bestehender ET-Im-

plementierungen einfach zu realisierende ET-Varianten (EET) entwickelt, die sehr eingangig auch fur

darin ungeubte Programmierer anwendbar sind. Daruber hinaus werden durch die Einfuhrung von Fast

Expression Templates (FET) die bestehenden Effizienzmangel der herkommlichen ET-Programmierung

behoben. Diese weiterentwickelte Implementierungstechnik unterstutzt durch ihre Programmierung den

Compiler beim Optimieren der geschachtelten Operationsobjekte. Dadurch ergeben sich mittels FET-

Bibliotheken leistungsfahige Programme, die auch auf Hoch- bzw. Hochstleistungsrechnern die Effizienz

von Implementierungen in C erreichen. Neben der Einfuhrung in einige weiterfuhrenden Techniken

werden zusatzlich die Ubersetzungszeiten von ET-Bibliotheken untersucht und beschleunigt.

Nach den grundlegenden Weiterentwicklungen von ET werden generelle Anwendungen der Tech-

nik zur Losung von partiellen Differentialgleichungen betrachtet. Insbesondere wird eine Template-

Bibliothek diskutiert, welche zur flexiblen, effizienten und intuitiven Berechnung lokaler Diskretisie-

rungssterne dient, die aus Finiten Element Ansatzen entstehen. Dabei werden die Implementierungs-

strategien und der Wirkungsumfang detailliert beschrieben. Zusatzlich werden einige aktuelle Problem-

stellungen dargestellt, in denen die Bibliothek Anwendung findet.

Die im Rahmen vorliegender Arbeit prasentierten Implementierungstechniken und deren Anwendun-

gen erleichtern die problemspezifische Entwicklung effizienter und benutzerfreundlicher Bibliotheken in

C++.

xiii

Page 14: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ZUSAMMENFASSUNG

xiv

Page 15: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ABSTRACT

Abstract

The Expression Templates (ET) implementation technique represents a powerful method for accom-

plishing efficient operator overloading in C++. Hence, the mathematical expressions are encapsulated

in template operation classes which allow for highly optimized evaluations. Based on the ET tech-

nique several powerful libraries were implemented, mainly for solving linear algebraic problems, and

moreover, programs for solving partial differential equations. Even if ET yield high efficient and easy

usable programs many scientific programmers hesitated to implement this technique. This was mainly

caused by the fault-prone and laborious coding of such problem-specific libraries. Furthermore, ET

implementations on high performance platforms still do not reach the expected efficiency.

In the scope of this thesis several basic enhancements are presented. Firstly, easy implementable

ET versions are discussed which can also be applied by programmers having low experience with

this technique. However, the presented versions of ET implementations require – in difference to the

common ET variants – only one overloaded version of each operator. As a consequence, the coding of

such libraries is faster and easier. The remaining performance lacks of common ET implementations

are focused by the introduction of Fast Expression Templates (FET). This advanced programming

technique supports the compiler in resolving nested template types. Hence, those FET-based libraries

achieve an efficiency of corresponding C-codes even on high performance platforms. In addition to the

FET technique, this thesis outlines some continuative techniques for a more general usage, as well as

the study of the compile times resulting from ET implementations.

After these fundamental enhancements of the ET programming technique we focus on the general

applications of the resulting methods for the numerical solution of partial differential equations. In

particular, a template library is discussed, that provides flexible, efficient and intuitive computation of

local stiffness matrices which arise from finite element discretizations. In addition, the implementation

policies and the features realized are described. Several application examples of the template library

are summarized.

The presented implementation techniques and their applications ease the problem-specific develop-

ment of efficient and user-friendly C++-libraries.

xv

Page 16: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ABSTRACT

xvi

Page 17: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 1. EINLEITUNG

1 Einleitung

1.1 Inhaltliche Ausrichtung

Die Ergebnisse der vorliegenden Arbeit dienen als Beitrag zu der einfachen Programmierung effizienter

und benutzerfreundlicher mathematischer Bibliotheken in C++. Der Fokus liegt dabei besonders auf

der Vereinfachung und Verbesserung von Implementierungstechniken, sowie deren Anwendungen in

praxisrelevanten Problemstellungen des wissenschaftlichen Rechnens. Im Rahmen der Weiterentwick-

lung und des erweiterten Einsatzes der Expression Templates (ET) Programmiertechnik werden die

folgenden Themengebiete behandelt:

• Analyse bestehender ET-Bibliotheken und Vereinfachung der ET-Programmierung, unter Ver-

meidung zusatzlicher Fehlerquellen bei der praktischen Realisierung

• Entwicklung und Untersuchung leistungsfahiger Implementierungsvarianten von ET fur eine ver-

lustfreie Verwendung auf Hoch- und Hochstleistungsrechnern

• Einsatz von ET zur Losung partieller Differentialgleichungen mit einer Detail-Studie an einer

Template-Bibliothek zur Berechnung lokaler Diskretisierungsmatrizen

1.2 Motivation

Die Erarbeitung realistischer und damit immer großerer und komplexer Simulationen praxisrelevanter

Problemstellungen stellt die Software-Entwickler in Industrie und Forschung vor standig neue Heraus-

forderungen. Parallel zu den wachsenden Aufgaben ist auch eine steigende Kapazitat der Rechenleis-

tung zu verzeichnen, die auch stetig kostengunstiger zu haben ist. Dies erfordert von Programmierern

sich mit immer komplexeren Losungsansatzen auseinander zu setzen, welche auch zu komplizierteren

und umfangreicheren Computerprogrammen fuhren. Beispielsweise umfassen aktuelle praxisbezogene

numerische Simulationen oft mehr als einer Million Zeilen an Programmcode. Des Weiteren sind diese

Anwendungen stetig zu warten bzw. zu erweitern.

1.2.1 Entwicklung numerischer Software

Aus Sicht des Entwicklers stellen umfangreiche numerische Anwendungen einen enormen implemen-

tierungstechnischen sowie programmierungsorganisatorischen Aufwand dar. Gerade in den Program-

miersprachen FORTRAN und C, in denen kaum sprachtechnische Mittel zur Verfugung stehen, um

eine Kapselung der Daten vorzunehmen, treten leicht Probleme mit der passenden Indizierung kom-

plizierter arraybasierter Datenstrukturen auf. Implementierungen mittels Zugriffsfunktionen oder auch

Makros, welche bereits eine gewisse Programmiersicherheit bieten, fuhren meist zu schwer lesbaren

Codes. Daruber hinaus ist eine strukturierte, modulare und dadurch ubersichtliche Programmierung

in FORTRAN oder C nur mit viel Programmierdisziplin moglich. Dabei sind gerade die Lesbarkeit und

eine gewisse Ubersichtlichkeit der Programme wichtig, wenn Wartungen, Anderungen oder Erweiterun-

gen der Software durchgefuhrt werden sollen. Vor diesem Hintergrund erfolgte eine Weiterentwicklung

der Programmiersprache C, die gerade fur die Implementierung großer Projekte geeignete Mittel bieten

sollte.

1

Page 18: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

1.2. MOTIVATION

Die Programmiersprache C++ fuhrte zur Unterstutzung der modularen Entwicklung von Software

objektorientierte Programmierparadigmen ein, welche die Definition von benutzereigenen Datentypen

sowie Datenkapselung und Vererbung ermoglichen [Str00]. Neben diesen neuen Mechanismen zum

strukturierten Erstellen von Programmen wurde C++ unter anderem durch eine strengere Typprufung,

dem Template-Mechanismus, dem Uberladen von Operatoren und dem Error-Handling erweitert. Trotz

der neuen Programmierparadigmen liefert C++ als Weiterentwicklung von C aber auch vergleichbar

leistungsstarke Programme, da die handwarenahe Programmierung wie in C weiterhin moglich ist.

Gerade die erreichbare Performance macht C++ fur numerische Problemstellungen interessanter als

andere Sprachen mit vergleichbaren Programmierparadigmen (z.B. Java).

Durch diese Verbesserung der Programmstrukturierung wurde C++ nach der Einfuhrung fur viele

komplexe Anwendungen herangezogen, so zum Beispiel fur Betriebssysteme, Datenbanken oder auch

zur Berechnung numerisch-mathematischer Problemstellungen. Gerade fur letztgenannte bietet C++

mit Templates und dem Operatoruberladen sehr geeignete Hilfsmittel, um die Programmierung und

Benutzung entsprechender Bibliotheken zu erleichtern. Mittels Templates werden Klassen mit Typen als

Parameter ausgestattet, so dass deren Grunddatentypen durch den Anwender festgelegt werden konnen.

Damit wurden die abstrakten Datentypen der Standard Template Library (STL) implementiert, die

direkt in anderen Codes verwendet werden konnen, um die Programmentwicklung zu beschleunigen.

Das Uberladen von Operatoren hingegen ermoglicht es intuitive Schnittstellen zu schaffen, die sehr nahe

an den mathematischen Formulierungen liegen, wodurch einfacher anwendbare Bibliotheken entstehen.

Außerdem wird der Code durch die in-order Schreibweise viel ubersichtlicher und lesbarer, wodurch

Fehler bei der Anwendung verringert werden.

Doch gerade fur eine effiziente Implementierung benutzerfreundlicher Schnittstellen in C++ fehlten

zunachst geeignete Konzepte, so dass leicht und intuitiv anwendbare Bibliotheken oft hinter der erwar-

teten Performance zuruckblieben. Speziell auf Hochleistungsrechnern ist in der Regel eine hardwarenahe

Programmierung, die kaum auf Benutzerfreundlichkeit ausgerichtet ist, notig, um die plattformspezifi-

schen Details ausnutzen zu konnen. Durch die weit gefassten Spracheigenschaften sind gewisse Optimie-

rungen in C++ nur sehr konservativ bzw. schwieriger als z.B. in FORTRAN durchzufuhren. Als Folge

wurde der Implementierung benutzerfreundlicher Software besonders im High-Performance-Computing

wenig Aufmerksamkeit zuteil, da die Effizienz der rechenaufwandigen Programme fur vorwiegend er-

gebnisorientierte Entwickler im Vordergrund steht.

1.2.2 Effiziente Implementierungen via ET

Durch die Einfuhrung der ET-Technik konnten einige der offensichtlichen Performance-Mangel des tra-

ditionellen Operatoruberladens in C++ behoben werden [Vel95]. Zum einen konnen dadurch die wenig

performanten, von C geerbten, Call-Back-Funktionen umgangen werden, zum anderen ergeben sich

gerade fur vektorbasierte Datenstrukturen Wege zur Vermeidung von lokalen Variablen wahrend der

Auswertung. Mittels ET werden Ausdrucksbaume aufgebaut, die in templatisierten Klassenobjekten

alle Typinformationen der Operationen und Operanden enthalten. Durch die damit durchfuhrbaren

Optimierungen werden besonders fur große Datenstrukturen leistungsstarke Programme erzielt, deren

Performance mit C-Codes vergleichbar ist.

Neben der Entwicklung mehrerer sehr performanter Bibliotheken entfachte sich wieder die Grund-

satzdiskussion, ob C++ mit seinen Programmierparadigmen wirklich mit der Performance von FORT-

RAN oder C konkurrieren kann [Vel97]. Trotz der großen Leistungssteigerung durch die Verwendung

von ET, konnte die Performance von C++-Programmen gerade auf Hochleistungsrechnern oft nicht

oder nur mit einer per Hand angepassten Implementierung erreicht werden.

Die ET-Technik wurde und wird oft nur zogerlich zur Programmierung mathematischer Software

herangezogen. Gerade das Implementieren der gangigen ET-Varianten erscheint zu Beginn sehr kompli-

ziert, und fuhrt bei falscher Benutzung zu sehr langen und oft kryptisch anmutenden Fehlermeldungen.

2

Page 19: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 1. EINLEITUNG

Daruber hinaus fuhren die vielen notigen Versionen von uberladenen Operatoren oft zu langwierigen

Programmcodes, deren Unvollstandigkeit wegen der anwendungsabhangigen Template-Instantiierung

meist erst durch entsprechende Tests aufgedeckt wird.

1.2.3 ET zur Losung partieller Differentialgleichungen

Ausgehend von der ET-Technik wurden einige sehr leistungsstarke und benutzerfreundliche Bibliothe-

ken entwickelt, vorwiegend zur effizienten Realisierung von vektorbasierten, mathematischen Daten-

strukturen und Berechnungen linearer Gleichungen.

Daneben entstanden zum Beispiel mit POOMA [Rum96] oder ExPDE [Pfl01] auch Bibliotheken

zur numerischen Losung von partiellen Differentialgleichungen. Durch die Verwendung von ET konn-

ten dabei auch komplizierte mathematische Ausdrucke wie etwa Differentialoperatoren effizient rea-

lisiert werden, wobei wiederum sehr problemnahe Schnittstellen entstanden. Gerade bei komplexeren

Problemstellungen in drei Dimensionen mit praxisnahen und daher meist unstrukturierten Diskreti-

sierungsgittern, resultieren oft komplizierte Datenstrukturen sowie Diskretisierungen der Operatoren.

Diese sind ohne entsprechende Datenkapselung nur sehr fehleranfallig zu implementieren. Dabei sind

es oft Entwickler aus Anwendungsgebieten wie Natur-, Ingenieur- oder Wirtschaftswissenschaften, die

praxisnahe Aufgabenstellungen losen wollen, jedoch wegen einer weniger fundierten Programmieraus-

bildung Probleme mit der strukturierten Programmentwicklung haben. Gerade fur solche Anwender

sind intuitive und benutzerfreundliche Bibliotheken sehr hilfreich, wobei dabei naturlich nicht auf eine

entsprechende Leistung verzichtet werden soll.

1.2.4 Weiterfuhrende ET-Techniken und Anwendungen

Aus diesen Grunden werden in der vorliegenden Arbeit Methoden zur einfacheren Realisierung von ET-

Bibliotheken prasentiert. Diese verkurzen einerseits die Implementierungen, da jeder Operator nur eine

uberladene Version benotigt. Andererseits ergeben sich auch weniger Verschachtelungen der Templates,

wodurch die Fehlerquellen der ET-Programmierung reduziert werden.

Aufbauend auf dieser einfachen Implementierungsvariante werden die Ursachen analysiert, welche die

Leistung von ET-Anwendungen beeintrachtigen. Die aufgedeckten Optimierungsmangel der betrach-

teten C++-Compiler werden durch eine Template-Nummerierung der Variablen vermieden. Mit dieser

Technik werden die Fast Expression Templates eingefuhrt, die eine rein typbasierte Implementierung

der ET ermoglichen. Dadurch erreichen ET-Bibliotheken insbesondere auch auf Hochleistungsrechnern

die erwartete Performance von Implementierungen im C-Stil.

Im Software-Paket Colsamm werden die werden die einfache, flexible und problembezogene Verwen-

dung der erarbeiteten Techniken demonstriert. Die Template-Bibliothek Colsamm erlaubt die effizien-

te und benutzerfreundliche Berechnung der lokalen Steifigkeitsmatrizen, die aus der Finiten Elemente

Diskretisierung von partiellen Differentialgleichungen entstehen. Durch das effiziente Uberladen von

mathematischen Operatoren ist eine sehr intuitiv einsetzbare sowie leicht erweiterbare Assemblierung

von Diskretisierungsmatrizen moglich, die aus Finiten Elemente Diskretisierungen entstehen.

1.3 Uberblick

Der thematische Rahmen dieser Arbeit gliedert sich in drei Teile: die Prasentation und Analyse be-

stehender ET-Implementierungen, die Weiterentwicklung der ET-Programmiertechnik selbst, und die

problembezogene Anwendung von ET zur Losung von partiellen Differentialgleichungen.

Zunachst werden die grundsatzlichen Untersuchungen und daraus resultierenden Weiterentwicklun-

gen der ET-Technik betrachtet. Dabei werden in Kapitel 2 die programmiertechnischen Grundlagen

in C++, Auszuge aus der Verwendung von Templates, Optimierungsmechanismen von C++-Compi-

lern und die der Arbeit zugrunde liegenden Programmcodes zusammengefasst. Kapitel 3 umfasst die

3

Page 20: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

1.3. UBERBLICK

Entwicklung der ET-Technik zur performanteren Realisierung des bis dato fur große Datenstrukturen

ineffizienten Operatoruberladens. Des Weiteren wird die traditionelle Art der Implementierung von

ET in C++ aufgezeigt, sowie gangige Varianten und bekannte ET-Bibliotheken vorgestellt. In Kapi-

tel 4 werden die verschiedenen Bestandteile einer ET-Implementierung analysiert, wobei zunachst die

Performance-Vorteile gegenuber den traditionellen Arten des Uberladens von Operatoren herausgear-

beitet werden. Zusatzlich wird die Lebensdauer von ET-Objekten untersucht.

Aufbauend auf diesen grundlegenden Analysen werden im zweiten Teil beginnend mit Kapitel 5

einfache sowie typsichere Implementierungen der ET-Technik entwickelt. Dazu werden zunachst die

wesentlichen Punkte der Programmiertechnik diskutiert, welche die Programmierung von ET ver-

komplizieren. Danach werden Methoden zur einfacheren Realisierung von ET prasentiert, die eine

typsichere Implementierung ohne unerwartete Mehrdeutigkeiten fur den Compiler ermoglicht. Durch

Herausarbeiten der bestehenden Performance-Probleme der aktuellen ET-Implementierungen wird in

Kapitel 6 die Methode der Fast Expression Templates (FET) entwickelt, zunachst unter Verwendung

von template-nummerierten Variablen, sowie darauf aufbauend eine rein typbasierte Variante. Die

Effizienz dieser FET-Implementierungen wird dann auf gangigen Rechnern sowie Hochleistungsrech-

nern mit der Performance von traditionellen ET-Varianten und reinen C-Codes ohne ET verglichen.

Abschließend werden noch einige praktische Programmierhinweise zur Anwendung der FET-Technik

aufgefuhrt. Kapitel 7 enthalt mehrere Methoden zum besseren Einsatz der ET- bzw. FET-Techniken.

Dies erstreckt sich uber die Typ-Minimierung mittels Traits, die Anwendung der ET auf verschiedenar-

tige Datenstrukturen und die Speicherung von ET-Ausdrucken als Objekte bzw. mittels Typkapselung.

Weiterhin behandelt werden Methoden zur sicheren Matrix-Vektor-Multiplikation. In Kapitel 8 wer-

den die Ubersetzungszeiten von ET-Programmen untersucht, sowie Implementierungsvarianten und

Techniken zur Verkurzung der Compilierungsdauer. Dabei steht vor allem die Untersuchung des GNU

C++-Compilers im Mittelpunkt. Abschließend fasst Kapitel 9 die erarbeiteten Weiterentwicklungen

der ET-Technik zusammen und diskutiert die Grenzen dieser Methode sowie die weitergehende An-

wendungen im wissenschaftlichen Rechnen.

Der dritte Teil dieser Arbeit umfasst die Anwendung der ET-Implementierungstechnik zur Losung

von partiellen Differentialgleichungen, insbesondere mittels der Finiten Elemente Methode (FEM). In

Kapitel 10 werden die Grundlagen der FEM unter Auflistung der einzelnen Schritte zur Durchfuhrung

einer FE-Diskretisierung erlautert. Kapitel 11 umfasst die Programmierung, die Funktionsweise und

den Programmaufbau der Template-Bibliothek Colsamm durch Vergleich mit den vorher zusammenge-

tragenen mathematischen Grundlagen der FEM. Anschließend werden einige Anwendungen von Col-

samm in praxisrelevanten Problemstellungen wie etwa im optischen Fluss oder der Berechnung von Di-

polmodellen von Gehirnstromen prasentiert. Kapitel 12 umfasst weitere Anwendungen der ET-Technik,

unter anderem Methoden zur Schleifenmanipulation, die Implementierung der logischen Verknupfung

von Gebieten. Als Abschluss fasst Kapitel 13 die prasentierten Ergebnisse zusammen und umreißt

weitere Einsatzgebiete und Anwendungsmoglichkeiten der ET-Technik.

4

Page 21: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

Teil I

Expression Templates – Grundlagen,

Entstehung und Analyse

Page 22: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen
Page 23: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 2. SPRACHGRUNDLAGEN UND PROGRAMMIERKONZEPTE

2 Sprachgrundlagen und

Programmierkonzepte

In den folgenden Abschnitten werden die programmiersprachlichen Grundlagen sowie die spater ange-

wendeten Techniken zur Realisierung domanenspezifischer Programmierung prasentiert und die dazu

notigen Implementierungstechniken in C++ zusammengefasst.

2.1 Domain-specific Embedded Languages

Eine domanenspezifische Programmiersprache (domain-specific language, DSL) beschreibt eine Pro-

grammiersprache, die sich zum Implementieren bestimmter Problemstellungen auf Grund der Schnitt-

stellen, der Funktionen und Performance, besonders gut eignet [VS06]. Dabei sind die softwaretech-

nischen Anforderungen der Programmentwicklung von der fachlichen Erstellung von Algorithmen ge-

trennt. Integriert man eine DSL in einer bestehenden Programmiersprache, so spricht man von einer

domain-specific embedded language (DSEL). Solche DSELs, die in eine bereits existierende Sprache

eingebettet sind, haben den Vorteil, dass sie durch gangige Compiler ubersetzt werden konnen. Diese

ubernehmen dann die komplette Syntax- und Semantikanalyse. Außerdem ist eine Programmierung

mit bereits bekannter Syntax moglich. Daruber hinaus sind DSEL-Implementierungen durch die Ver-

breitung der bestehenden Compiler sehr leicht auf verschiedene Plattformen portierbar.

Zur Realisierung solcher DSEL fur mathematische Problemstellungen bietet C++ mit dem Uberladen

von Operatoren eine Moglichkeit, um sehr intuitive mathematische Schnittstellen zu definieren. Der

entscheidende Vorteil der Verwendung von Operatoren anstatt herkommlicher Funktionen liegt in der

in-order Schreibweise (Operand - Operator - Operand), was der naturlichen mathematischen Notation

entspricht. Bei entsprechender Definition konnen die Operatoren auch mit vollig neuen Bedeutungen

ausgestattet werden, wobei hierbei darauf zu achten ist, dass die Verstandlichkeit der Implementierung

bestehen bleibt.

2.2 Benutzerfreundliche, mathematische Schnittstellen

In C++ konnen zu einer Funktion mehrere Varianten mit gleichen Funktionsnamen definiert werden,

die sich jedoch in ihrer Parameterliste unterscheiden mussen [Str00]. Dieses sog. Uberladen von Funk-

tionen ermoglicht es beim Programmieren einheitlich benannte Schnittstellen zu schaffen, die jedoch

entsprechend der eingesetzten Parameter ganz unterschiedliche Implementierungen und Wirkungen

haben konnen. Damit wird die Verwendung einer entsprechend angelegten Bibliothek einfacher, da

der Anwender nicht erst die zum jeweiligen Problem passende Funktion suchen muss. Zusammen mit

dem spater aufgefuhrten Template-Mechanismus sowie der Template-Spezialisierung kann dies als sehr

geschicktes Mittel eingesetzt werden, um komplizierte Datentypen verarbeiten zu konnen [AG05], ohne

bei der Benutzung die exakten Typ angeben zu mussen.

Funktionen konnen nur mittels unterschiedlicher Parameterlisten uberladen werden, wobei auch die

internen Typkonvertierungen beim Implementieren zu berucksichtigen sind, um eventuelle Mehrdeutig-

keiten beim Ubersetzen zu vermeiden. Ein Uberladen ausschließlich bezuglich des Ruckgabetyps einer

Funktion ist nicht moglich, da ein Funktionsaufruf nach dem C++-Standard kontextunabhangig sein

7

Page 24: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

2.2. BENUTZERFREUNDLICHE, MATHEMATISCHE SCHNITTSTELLEN

soll, d.h. der Aufruf einer Funktion mit den identischen Parametern in jedem Kontext zu dem gleichen

Ergebnistyp fuhren muss.

Finden sich beim Ubersetzen eines Programms zu einem Funktionsnamen mehrere Varianten mit

unterschiedlichen Parameterlisten, so bestimmt der Compiler diejenige uberladene Version der Funkti-

on, deren Parametertypen am besten zum aktuellen Funktionsaufruf passen. Dazu definiert der C++

Standard zur Bestimmung der passenden Funktion den folgenden festgelegten Ablauf von untersuchten

Kriterien [Str00]:

1. Genaue Ubereinstimmung der Parametertypen bzw. uber die Anwendung trivialer Konvertie-

rungen auflosbar (Array-Name nach Zeiger, Funktionsname nach Funktionszeiger und T nach

const T).

2. Identifikation der Typen mittels sog. Promotionen (Umwandeln in einen sinnvollen, großeren Typ

(bool nach int , char nach int , short nach int sowie entsprechende Umwandlungen mit unsigned; float

nach double und double nach long double)

3. Eine Ubereinstimmung der Typen der Parameterliste nach Anwendung bestimmter Standard-

konvertierungen (z.B. int nach double, Abgeleitete Klasse * nach Basis Klasse*).

4. Ubereinstimmung der Parametertypen nach der Anwendung von benutzerdefinierten Konvertie-

rungsoperatoren (siehe Abschnitt 2.2.2).

5. Ubereinstimmung mittels der Erweiterung fur eine variable Anzahl von Parametern in einer

Funktionsdeklaration (z.B. void foo( int a, ...) ).

Nur wenn der Compiler mittels Durchlauf dieser Liste genau eine Ubereinstimmung findet, kann er

die passende Funktion bestimmen und entsprechend ubersetzen. Beim Behandeln von uberladenen

Funktionen konnen sich nach dieser Liste aber auch Mehrdeutigkeiten ergeben, die zu einem Fehler

beim Ubersetzen fuhren und vom Programmierer bereinigt werden mussen.

Neben dem Uberladen von Operatoren gibt es noch eine weitere Variante zur Programmierung

flexibler Funktionsschnittstellen, die Definition von Default-Parametern. Beginnend vom Ende der

Parameterliste einer Funktion konnen in Funktionsdeklaration Werte angegeben werden, die eingesetzt

werden, falls das entsprechende Argument beim Aufruf nicht ubergeben wird. Werden solche Default-

Parameter verwendet, mussen diese luckenlos vom letzten Parameter an definiert werden, bis zu dem

ersten Parameter, fur den kein Defaultwert vorgegeben werden soll.

2.2.1 Uberladen von Operatoren

Die Programmierung in C++ erlaubt neben dem Uberladen von Funktionen auch einen Großteil der

gangigen, zumeist mathematischen Operatoren fur benutzerdefinierte Datentypen neu zu definieren

[Str00]. Grundsatzlich werden diese Operatoren genauso wie Funktionen uberladen, indem Versio-

nen der Operatoren mit unterschiedlichen Parametertypen deklariert werden. Bis auf den Klammer-

Operator (operator()) haben jedoch alle Operatoren eine feste Anzahl von Parametern, die nicht ver-

andert werden kann. Bei der Suche nach derjenigen uberladenen Version, deren Parameterliste am

besten mit den Argumenten des aktuellen Aufrufs des Operators ubereinstimmt, werden die selben

Konvertierungsregeln angewandt, wie sie zuvor fur herkommliche Funktionen aufgefuhrt sind. Trotz

der Ahnlichkeit haben Operatoren noch einige Besonderheiten, die in der folgenden Auflistung kurz

zusammengefasst werden.

• Die Mehrheit der Operatoren kann entweder als Nicht-Elementfunktion oder Memberfunktion

definiert werden. Bei der Deklaration der Operatoren als Memberfunktionen fungiert das this -

Objekt als linker Operand. Alle Zuweisungsoperatoren, sowie die Operatoren operator[ ], operator()

und operator−>, mussen jedoch als nicht-statische Elementfunktionen definiert werden um sicher-

zustellen, dass es sich beim ersten Operanden um ein veranderbares Objekt ( lvalue ) handelt.

8

Page 25: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 2. SPRACHGRUNDLAGEN UND PROGRAMMIERKONZEPTE

• Durch das Uberladen kann die Wirkung von Operatoren neu definiert werden. Trotz der neuen

Funktionsweise bleibt die durch C++ definierte Prioritatenregelung der Operatoren erhalten. Es

gilt also weiterhin Punkt vor Strich. Auch die weiteren Operatoren, die noch uberladen wer-

den konnen, haben eine festgesetzte Prioritat, die nicht verandert werden kann. Eine komplette

Prioritatenliste findet man ebenfalls in [Str00].

• Operatoren haben die sehr benutzerfreundliche Eigenschaft, dass sie – anders als Funktionen oder

Klassenmethoden – in in-order Notation verwendet werden. Diese Schreibweise entspricht genau

der mathematischen Formulierung, was naturlich die Implementierung numerischer Probleme

wesentlich erleichtern kann. Dabei ist jedoch bei binaren Operatoren noch zu beachten, dass im

Standard nicht festgelegt ist, ob zuerst der erste oder der zweite Operand ausgewertet wird.

2.2.2 Benutzerdefinierte Konvertierungsoperatoren

Zusatzlich zu den Operatoren in C++ wird die Definition von benutzerdefinierten Konvertierungsope-

ratoren zum Spezifizieren von Typumwandlungen betrachtet. Die Umwandlungen eines Datentyps in

einen anderen sind in C++ wegen der strengen Typprufung sehr eingeschrankt. So sind nach dem

Standard nur bestimmte Konvertierungen der fundamentalen Datentypen moglich, sowie eine Kon-

vertierung eines abgeleiteten Typs in den Basisklassentyp. Sollen nun zusatzliche Casts eingefuhrt

werden, so kann dies teilweise durch die Definition entsprechender Konstruktoren erreicht werden.

Folgende Falle konnen aber nicht mittels Konstruktoren realisiert werden [Str00]:

• die implizite Konvertierung eines benutzerdefinierten Typs in einen fundamentalen Typ, und

• eine Konvertierung in eine bereits definierte Klasse, ohne die bestehende Klasse zu verandern.

Fur diese Falle ist die Einfuhrung von klassenspezifischen Konvertierungsoperatoren moglich, welche

die Umwandlung eines Objekts einer neu definierten Klasse in einen bereits bestehenden Datentyp

definieren. Mittels dieser Cast-Operatoren kann gezielt die Umwandlung zwischen Typen eingefuhrt

werden, die der Compiler nicht von selbst auflosen kann.

Ist TYPE ein fundamentaler Datentyp oder eine bereits definierte Klasse, so kann man einen solchen

Konvertierungsoperator folgendermaßen definieren:

c l a s s X . . .

ope ra to r TYPE ( ) ;

;

X : : ope ra to r TYPE ( ) . . .

Dabei ist besonders zu bemerken, dass der Cast-Operator keinen Ruckgabetyp besitzt. Zusatzlich

kann man auch die Umwandlung von konstanten Objekten oder auch Zeigern oder Referenzen auf

Objekte spezifizieren, z.B.:

c l a s s X

. . .

ope ra to r const TYPE& () const ;

;

Dieser Cast-Operator wird dann in all jenen Fallen aufgerufen, in denen der Compiler diese Um-

wandlung benotigt um das aktuelle Objekt in den passenden Typ umzuwandeln. Das geschieht unter

anderem auch bei expliziten Casts, z.B. static cast . Allgemein wird dazu geraten, solche benutzerdefi-

nierten Cast-Operatoren nur sehr gezielt einzusetzen, andernfalls kann dies leicht zu undurchsichtigen

Mehrdeutigkeiten fur den Compiler fuhren.

9

Page 26: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

2.3. TEMPLATES IN C++

2.3 Templates in C++

Das Einsetzen von Datentypen als Klassenparameter in C++ wird Template (Schablone) genannt. Die-

se Moglichkeit wurde erst spater in den Sprachstandard aufgenommen, hauptsachlich um die Definition

von typunabhangigen Datenstrukturen zu verbessern.

Die strenge Typkontrolle in C++ verlangt vom Programmierer, dass Variablen, Parameter und

Ruckgabewerte von Funktionen mittels spezifischen Typen deklariert werden. Es gibt jedoch viele

Algorithmen, die trotz verschiedener Grunddatentypen gleich oder sehr ahnlich implementiert werden.

Als Beispiel stelle man sich hierzu die Realisierung von Sortieralgorithmen oder Container-Klassen vor.

Will man in C oder C++ (ohne Templates) solche Programme nicht fur jeden benotigten Typ aus-

schreiben, so gibt es zwei Varianten, um mit allgemeinen Grunddatentypen arbeiten zu konnen. Man

konnte entweder mit typunsicheren void*-Zeigern arbeiten, oder sich entsprechende Makros definieren,

welche den aktuellen Typ fur den aktuellen Programmlauf ersetzen. Doch diese herkommlichen Losun-

gen haben genauer betrachtet entscheidende Nachteile. Bei der Programmierung mit void*-Zeigern kann

der Compiler fur diesen Teil nur noch eine sehr eingeschrankte Typprufung durchfuhren. Daruber hin-

aus sind fur diese void*-Variablen keine Datentypgroßen und keine Klassenmethoden bekannt, und die

Programmcodes werden schwer lesbar. Auch die Verwendung von Makros halt die Implementierung

kurz, doch ist die Arbeit mit diesem einfachen Ersetzungsmechanismus fehleranfallig, da eine Syntax-

prufung erst nach dem Precompiling durchgefuhrt wird. Dies fuhrt meist zu schwer nachvollziehbaren

Fehlermeldungen, da sie sich nicht auf den ursprunglichen Programmcode beziehen [VJ03].

Zur Verbesserung dieser Implementierungstechniken wurde mit dem Template-Mechanismus ein ge-

nerisches Programmierparadigma in den C++-Sprachstandard eingefuhrt, welches die Flexibilitat der

void*-Zeiger bzgl. der Typwahl sowie eine vollstandige Typprufung erfullt. Templates ermoglichen die

Definition von Funktionen und Klassen, die von einem oder mehreren Typparametern abhangen. Um

namentliche Verwechslungen mit den Parametern der Argumentliste einer Funktion auszuschließen,

werden die Typparameter im Weiteren als Template-Parameter bezeichnet. Daneben heißen Funktio-

nen oder Klassen mit Template-Parametern templatisierte Funktionen bzw. Klassen.

Die Programmierung mit Templates erlaubt eine Implementierung ohne den zugrunde liegenden

Datentyp spezifizieren zu mussen. Die Festlegung des verwendeten Template-Typs findet erst bei der

Verwendung des templatisierten Codes statt, wobei die Semantikanalyse nur von den Eigenschaften des

tatsachlich verwendeten Typs abhangig ist. Da die Typspezifizierungen bereits zur Ubersetzungszeit

feststehen, kann der Compiler eine vollstandige Semantik- sowie Typprufung durchfuhren. Bei der

Definition und Verwendung von templatisierten Klassen und Funktionen treten einige Besonderheiten

auf, die im Folgenden kurz zusammengefasst werden.

2.3.1 Definition von templatisierten Klassen und Funktionen

Nach dem C++-Standard konnen Integer- und Enumerationswerte, sowie fundamentale und benut-

zerdefinierte Datentypen als Template-Typen verwendet werden. Die Deklaration von templatisier-

ten Klassen und Funktionen geschieht durch das Schlusselwort template, gefolgt von der Template-

Parameterliste in spitzen Klammern. Dabei kann fur einen Datentyp entweder eines der Schlusselworte

class oder typename verwendet werden. Im Rahmen dieser Arbeit wird class immer fur benutzerdefinierte

Datentypen benutzt, typename nur fur fundamentale Typen eingesetzt.

// Template I n t e g e r

template < i n t I n t eg e rVa l u e > c l a s s X 1 ;

// Template bekommt e i n en fundamenta len Datentyp

template <typename A> c l a s s X 2 ;

// Template−L i s t e mehre r e r b e n u t z e r d e f i n i e r t e r Datentypen

template <c l a s s A, c l a s s B> c l a s s X 3 ;

10

Page 27: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 2. SPRACHGRUNDLAGEN UND PROGRAMMIERKONZEPTE

Die Deklarationen von Funktionen mit Template-Parametern werden analog gehandhabt. Die Tem-

plate-Technik in C++ bietet einige spezifische Anwendungsmoglichkeiten, die im Folgenden umrissen

werden. Die nachstehende Aufstellung dient als Darstellung der wichtigen Aspekte von Templates,

bietet aber keine vollstandige Beschreibung der Technik. Dazu wird auf [VJ03] verweisen.

• Ahnlich wie bei der Definition der Argumentlisten von Funktionen, konnen auch fur Template-

Parameter Defaultwerte angegeben werden. Die Definition von Default-Templates ist nur am

Ende der Template-Parameterliste moglich. Beim Auflosen der Liste der Templates gelten die

gleichen Regeln wie bei den Default-Funktionswerten.

• Verwendet man templatisierte Klassen in einem Programm, mussen alle Template-Parameter

angegeben werden, die nicht durch Defaultwerte festgelegt sind. Die Templates werden in spitzen

Klammern nach dem Klassennamen aufgefuhrt. Sollte eine komplette Liste mit Default-Templates

definiert sein, mussen nach dem Klassennamen dennoch die leeren spitzen Klammern angegeben

werden. Ist ein Template-Argument selbst ein templatisierter Datentyp, muss darauf geachtet

werden, dass zwischen zwei spitzen Klammern immer ein Leerzeichen stehen muss.

• Funktionen haben im Vergleich zu Klassen den Vorteil, dass die Templates aus der Parameterlis-

te bestimmt werden konnen (type deduction). Dabei muss keine explizite Angabe der Templates

beim Aufruf der Funktion geschrieben werden, wenn der C++-Compiler die Typen der Template-

Parameter komplett aus der Argumentliste ableiten kann. Daruber hinaus ist es trotzdem moglich,

templatisierte Funktionen zu verwenden, deren Template-Parameter nicht vollstandig durch die

Parameterliste festgelegt sind. Diese mussen dann zusatzlich beim Aufruf angegeben werden. Im

Falle von objektunabhangigen Funktionen werden Template-Parameter – analog zu den Klassen

– in spitzen Klammern nach dem Funktionsnamen angegeben. Bei templatisierten Klassenmetho-

den muss dem Compiler mit dem Schlusselwort template unmittelbar vor dem Funktionsnamen

signalisiert werden, dass es sich um einen Funktionsaufruf handelt [Str00]. Sind die Templates teil-

weise durch die Funktionsargumente festgelegt, so gelten die gleichen Auflosungsbestimmungen

wie bei den Default-Template-Parametern.

• Fur templatisierte Klassen und Funktionen konnen Spezialisierungen, fur Template-Klassen auch

partielle Spezialisierungen definiert werden, um dadurch fur bestimmte Template-Argumente ge-

sonderte Implementierungen zu verwenden. Dazu definiert man die (partielle) Spezialisierung

mit Angabe der festen Template-Parameter. Der Compiler wahlt bei entsprechenden Template-

Parametern die passende (Teil-)Spezialiserung aus und vervollstandig gegebenenfalls die Instan-

tiierung. Dabei ist jedoch darauf zu achten, dass bei mehreren Template-Parametern keine Mehr-

deutigkeiten fur den Compiler entstehen [Str00].

2.3.2 Template-Instantiierung

Ein Programmcode, der von Templates abhangt, wird nach dem C++-Standard nur dann erzeugt,

wenn er in der Implementierung benotigt wird. Bei templatisierten Klassen und Funktionen sorgt der

Compiler implizit dafur, dass die notigen Instantiierungen bzgl. des eingesetzten Datentyps bei ihrem

ersten Aufruf zur Verfugung stehen. Dabei werden aber im Falle einer Template-Klasse nur die Member-

Templates erzeugt, die auch wirklich im weiteren Programm aufgerufen werden. Dies bedeutet, dass

man templatisierte Implementierungen mit Datentypen initialisieren kann, die bestimmte Methoden

des Template-Codes gar nicht zur Verfugung stellen. Diese zum Teil unvollstandige Instantiierung

fuhrt naturlich bei der Softwareentwicklung zu dem Nachteil, dass der Programmierer nur schwer die

Robustheit seiner Implementierung uberprufen kann. Konkrete Semantik-Fehler kann der Compiler

nur bei entsprechenden Instantiierungen entdecken.

Zusatzlich zur impliziten Code-Erzeugung des Compilers kann bei einer templatisierten Klasse oder

Funktion auch eine explizite Instantiierung erfolgen. Damit kann der Programmierer sicherstellen, dass

11

Page 28: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

2.3. TEMPLATES IN C++

der Code fur bestimmte Datentypen auch sicherlich erzeugt wird. So kann man bei der Entwicklung

von Software-Bibliotheken gewissen Mangeln der Instantiierung vorbeugen.

Die templatisierten Implementierungen werden beim Instantiieren in zwei Stufen uberpruft. Zunachst

wird der generische Programmcode (ohne eingesetzte Datentypen) auf Fehler in der Syntax untersucht.

Nach der Instantiierung wird zusatzlich der erzeugte Code auf kontextabhangige Semantik, wie zum

Beispiel verwendete Methoden oder Operationen uberpruft.

Wegen der zugrunde liegenden Trennung von Implementierung und Instantiierung muss der Com-

piler wahrend des Ubersetzens den kompletten templatisierten Programmcode kennen. Es genugt nun

nicht mehr, wie sonst ublich, die Deklarationen in einer Header-Datei zu kapseln, die dann alleine in die

notigen Programme eingebunden wird. Vielmehr mussen alle Implementierungen, die von Templates

abhangen, wahrend des Instantiierungsschrittes verfugbar sein. Dabei sorgt jedoch der Compiler bei

Programmen mit mehreren Ubersetzungseinheiten dafur, dass keine Mehrfach-Instantiierungen von

templatisierten Klassen mit den gleichen Template-Parametern auftreten.

2.3.3 Meta-Template-Programmierung

Die Template-Programmierung in C++ eroffnet mit den generischen Paradigmen ein weiteres wichtiges

Feld der Code-Entwicklung, die Erzeugung von Programmen zur Ubersetzungszeit. Diese sog. Meta-

Programmierung bezeichnet die Implementierung von Programmen, die dazu dienen neue Programme

zu generieren [AG05]. Die Besonderheit der Verwendung von Templates in C++ besteht darin, dass

diese Programmerzeugung wahrend der Ubersetzungszeit stattfindet.

Da durch Template-Spezialisierungen, je nach den eingesetzten Typen, verschiedene Programm-

teile instantiiert werden, kann somit sukzessive eine Codegenerierung erreicht werden. Dadurch wird

wahrend der Ubersetzungszeit ein Programmcode erzeugt, der anschließend vom C++-Compiler weiter

ubersetzt werden kann.

2.3.4 Traits

Eine besondere Anwendung finden die (partiellen) Spezialisierungen von templatisierten Klassen bei

der Implementierung von sog. Traits. Diese erlauben die Abbildung von Typinformationen auf Werte,

Funktionen und Typen, beschrieben unter anderem in [AG05].

Betrachten wir dazu als einfaches Beispiel einen Programmcode, mittels dem bestimmt werden kann,

ob es sich bei einem eingesetzten Typen um einen Integer handelt. Dazu benutzen wir die Klasse

Is Integer , die einen booleschen Wert hat, der im allgemeinen Fall auf false und nur fur die Spezialisie-

rung fur int auf true gesetzt wird.

template <typename Type>

s t r u c t I s I n t e g e r

s t a t i c boo l i s i n t e g e r = f a l s e ;

;

template < >

s t r u c t I s I n t e g e r <i n t >

s t a t i c boo l i s i n t e g e r = t rue ;

;

Damit kann nun bestimmt werden, ob es sich bei einem eingesetzten Datentyp um einen Integer

handelt oder nicht. Sinnvoll ist dies besonders in templatisierten Klassen oder Funktionen, in denen

nur fur bestimmte Datentypen – hier Integer – eine zusatzliche Funktionalitat eingefuhrt werden soll,

ohne eine explizite Spezialisierung. Da diese Auswertung bereits zur Ubersetzungszeit stattfindet, sind

damit auch Abbildungen von Template-Parametern auf Typen moglich, die als Template-Argumente in

eine templatisierte Klasse eingesetzt werden. Traits finden besonders in der Meta-Template-Bibliothek

BOOST [DA03] eine breite Anwendung. Hier werden Sammlungen von templatisierten Klassen und

12

Page 29: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 2. SPRACHGRUNDLAGEN UND PROGRAMMIERKONZEPTE

entsprechende Spezialisierungen bereit gestellt, die eine Vielzahl der wichtigen Auswertungen von Ty-

pen implementieren.

template <typename Type>

c l a s s DataSt ruc tu r e

boo l i n t e g e r ;

. . .

. . .

i n t e g e r = I s I n t e g e r <Type > : : i s i n t e g e r ;

;

2.3.5 Templategesteuerte Vererbung

Vererbung und Polymorphie stellen fur die Implementierung benutzerfreundlicher Software ein weiteres

wichtiges Feature dar. Dadurch ist es moglich, einheitliche Schnittstellen zu definieren, sowie objek-

torientierte Abstraktionen einzufuhren. Leider haben Implementierungen mittels abstrakter Klassen

den Nachteil, dass bei virtuellen Funktionen nur eine spate Bindung zur Laufzeit moglich ist. Gerade

bei der Verwendung von Funktionen mit einfachem Funktionsrumpf und haufigem Aufruf fuhrt dies zu

einem großen Overhead, der die Leistung eines Programms entscheidend beeintrachtigt. Optimierungen

wie Inlining sind bei einer spaten Bindung nicht moglich.

Eine Vererbung in Abhangigkeit von Template-Parametern bildet eine wichtige Grundlage fur leis-

tungsfahige Programme. Durch die bekannten Typinformationen kann eine dynamische Bindung ver-

mieden werden. Dabei kann die Basisklasse von den Template-Argumenten der Ableitung abhangen,

bzw. einer dieser Template-Parameter selbst Basisklasse werden. Mittels diesen template-abhangigen

Vererbungen lassen sich je nach eingesetzten Template-Parametern die Spezialisierungen von templati-

sierten Klassen zu davon abgeleiteten Klassen dazufugen. Besonders interessant ist dies bei Implemen-

tierungen fur unterschiedlich dimensionale Problemstellungen, bei denen anbangig von der Dimension

verschiedene Berechnungsformeln verwendet werden mussen.

template <c l a s s X>

c l a s s A . . . ;

template <c l a s s X>

c l a s s B : pub l i c X, pub l i c A<X> . . . ;

2.3.6 CRTP (Curiously Recurring Template Pattern)

Dienen die abstrakten Klassen einer Bibliothek lediglich als Schnittstellen fur die Parameterubergabe in

Funktionen oder Memberfunktionen, so kann jedoch eine besser optimierbare Vererbung implementiert

werden. Diese sog. CRTP-Technik wird oft in Kombination mit dem Barton-Nackman-Trick prasentiert

und oft auch mit diesem verwechselt [VJ03].

template <c l a s s A>

s t r u c t Bas e C l a s s

const A& ca s t ( ) const r e t u r n s t a t i c c a s t <const A&>(∗ t h i s ) ;

;

. . .

c l a s s De r i v a t i v e : pub l i c Base C la s s <De r i v a t i v e > . . . ;

Die CRTP-Technik implementiert einen Vererbungsmechanismus der bereits zur Ubersetzungszeit

aufgelost werden kann. Dazu muss eine templatisierte Basisklasse definiert werden, die bei der Ver-

erbung den Typ der abgeleiteten Klasse als Template-Typ erhalt. Dadurch kann jedes Objekt der

Basisklasse in den Typ des aktuellen abgeleiteten Objekts umgewandelt werden. Somit kann der Com-

piler die notigen Typen der Objekte bestimmen und alle ublichen Optimierungen durchfuhren.

13

Page 30: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

2.4. OPTIMIERUNGEN VON C++-COMPILERN

Mittels der CRTP-Implementierung kann also jedes Objekt der Basisklasse – der Typ der abgelei-

teten Klasse ist bekannt – in ein Objekt des Typs der abgeleiteten Klasse umgewandelt werden. Die

Verwendung vor einem Funktionsaufruf sieht damit folgendermaßen aus:

template <c l a s s A>

vo id f oo ( const Base C la s s <A>& ob j e c t )

ob j e c t . c a s t ( ) . bar ( ) ;

;

Zusatzlich konnen fur Situationen, in denen das abgeleitete Objekt als Argument in Funktionen oder

Konstruktoren ubergeben werden soll, automatische Konvertierungen einfuhrt werden. Dazu wird in

der Basisklasse ein Cast-Operator definiert, der im Wesentlichen die Funktion des vorher gezeigten cast

ubernimmt.

template <c l a s s A>

s t r u c t Bas e C l a s s

ope ra to r const A& () const

r e t u r n ∗ s t a t i c c a s t <const A∗>( t h i s ) ;

;

Hierbei ist besonders darauf zu achten, dass der static cast uber eine Konvertierung der Zeiger aus-

gefuhrt wird, nicht durch eine Umwandlung der Referenzen. Sonst kann es – bei machen Compilern,

z.B. Intel Compiler oder alteren GNU Versionen – passieren, dass dieser Operator sich selbst aufruft,

was vom Compiler nicht aufgedeckt werden kann. Dadurch, dass der static cast intern mit den Zeigern

auf das Objekt aufgerufen wird, umgeht man dieses Problem. Insgesamt ist es damit fur den Compi-

ler moglich, ein Objekt vom Typ der Basisklasse in den abgeleiteten Typ umzuwandeln, wenn dieser

innerhalb von Funktionsparametern benotigt wird.

2.4 Optimierungen von C++-Compilern

Da die Implementierungstechniken dieser Arbeit darauf ausgelegt sind, effiziente Programmcodes zu

ergeben, werden neben der richtigen Art und Weise der Programmierung auch leistungsstarke Optimie-

rungsmechanismen der Compiler benotigt. Nachfolgend werden einige ausgewahlte, fur das Verstandnis

dieser Arbeit wichtige, Optimierungskonzepte vorgestellt.

2.4.1 Elimination temporarer Objekte

Die Bezeichnung temporare Objekte umfasst im Rahmen dieses Teilabschnitts Werte, die wahrend des

Programmlaufs auf dem Stack abgelegt werden. Das Erzeugen und Zerstoren der temporaren Objek-

te kann je nach Typ durchaus hohe Kosten erzeugen und so die Performance eines Programms sehr

beeintrachtigen. In der (deutschsprachigen) Literatur werden auch lokale Objekte als temporar bezeich-

net, doch sind die lokalen Objekte von den nachstehenden Optimierungen nicht betroffen. Prinzipiell

kann man die Situationen, die den Compiler dazu zwingen temporare Objekte zu erzeugen, auf drei

wesentliche Ursachen zuruckfuhren.

Parameterubergabe bei Funktionen

Die Ubergabe by value von Objekten in Funktionsparametern hat die Erzeugung eines temporaren

Objektes zur Folge, wenn keine zusatzlichen Optimierungen angewandt werden. Betrachten wir zum

Beispiel eine Funktion, die als Ubergabeparameter ein Objekt vom Typ complex<double> besitzt, und

folgendermaßen deklariert wird.

14

Page 31: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 2. SPRACHGRUNDLAGEN UND PROGRAMMIERKONZEPTE

vo id f oo ( s t d : : complex<double> v a l u e ) ; // by v a l u e

In diesem Fall wird bei jedem Aufruf der Funktion foo das ubergebene complex<double>-Objekt kopiert.

Je nach Große des Objekts und je nach Haufigkeit der Aufrufe der Funktion kann dies die Effizienz der

Programmierung beeintrachtigen. Viele C++-Compiler konnen in diesen Fallen zwar durch entspre-

chende Optimierungen die Erzeugung von temporaren Objekten vermeiden, doch durch eine Ubergabe

by reference kann die Programmierung so abgeandert werden, dass keinerlei temporare Objekte ent-

stehen.

vo id f oo ( const s t d : : complex<double>∗ v a l u e ) ; // by r e f e r e n c e

vo id f oo ( const s t d : : complex<double>& va l u e ) ; // by r e f e r e n c e

Die Deklarierung als const garantiert dabei, dass auf das ubergebene Objekt in der Funktion nicht

schreibend zugegriffen werden darf und dieses so unverandert bleibt.

Temporare Objekte bei impliziter Typkonvertierung

Ruft man die obige Funktion statt mit einem komplexen Wert mit einem Wert vom Typ double auf,

so verwendet der Compiler implizit noch den entsprechenden Konstruktor der Klasse complex, der aus

einem double ein Objekt vom Typ complex<double> erzeugt.

f oo ( 1 . ) ; // r u f t i n t e r n den Kons t rukto r complex ( doub l e ) au f

Durch diese implizite Konvertierung der Variablen, die lediglich fur die Parameterubergabe benotigt

wird, entsteht wiederum ein temporares Objekt. Ahnlich zum vorherigen Fall konnen aber viele Com-

piler auch hier Optimierungen ansetzen und diese Erzeugung temporarer Objekte vermeiden.

Wie bereits erwahnt, kann der Compiler nur gewisse Konvertierungen implizit durchfuhren. Darunter

fallt – wie hier – der Aufruf entsprechender Konstruktoren, der aber dadurch vermieden werden kann,

indem die Konstruktoren als explicit deklariert werden. Somit durfen diese Konstruktoren nicht fur

die Typkonvertierung verwendet werden. Benutzerdefinierte Konvertierungsoperatoren dagegen werden

speziell dafur eingefuhrt, dem Compiler zusatzliche Umwandlungen zu ermoglichen. Außerdem konnen

diese zusatzlichen Konvertierungsoperatoren in bestimmten Fallen so definiert werden, dass sie lediglich

(konstante) Referenzen zuruckgeben und keine vollen Objekte. Damit wird ein zusatzliches Erzeugen

von temporaren Objekten verhindert.

Ruckgabewert-Optimierung

Wird innerhalb eines Funktionsrumpfes ein Objekt erzeugt, das den Ruckgabewert einer Funktion bil-

den soll, so kann die Ruckgabe nicht by reference erfolgen, da das lokal erzeugte Objekt nach Verlassen

der Funktion wieder geloscht wird. Also muss in diesen Fallen eine Ruckgabe by value erfolgen, die

aber wieder durch eine Ruckgabewert-Optimierung des Compilers beim Ubersetzen behoben werden

kann.

s t d : : complex<double> foo2 ( ) r e t u r n s t d : : complex<double > ( 1 . ) ;

2.4.2 Inlining

Die Optimierungen mittels Inlining von Funktionen sind eine Methode zur Reduzierung der Kosten von

Funktionsaufrufen. Durch Voranstellen des Schlusselwortes inline wird dem Compiler angegeben, dass

die Funktion bei jedem ihrer Aufrufe durch ihren Funktionsrumpf ersetzt werden soll. Die Definition

einer Inline-Funktion muss dem Compiler in jedem Ubersetzungsabschnitt zur Verfugung stehen, da die

Funktionsdefinition fur die Optimierung komplett bekannt sein muss. Bei Methoden, die innerhalb der

Klasse definiert werden, geschieht das Inlining im Allgemeinen automatisch. Dagegen ist ein Inlining

15

Page 32: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

2.4. OPTIMIERUNGEN VON C++-COMPILERN

bei virtuellen Funktionen nicht moglich, da beim Compilieren noch nicht bekannt ist, welche Funktion

tatsachlich aufgerufen werden soll.

Ist eine (Member-)Funktion als inline deklariert, so fugt der Compiler also den Rumpf der Funktion

– im Prinzip – an der Stelle ihrer Benutzung ein. Der so optimierte Programmcode kommt fur diese

Funktionen ohne den Aufruf und den Sprung an die entsprechende Speicherstelle, an der die Funktion

liegt, aus. Daruber hinaus kann der Compiler nun uber die Grenzen der Funktion hinweg optimieren,

z.B. Auswertung von Konstanten, Bestimmung von Abhangigkeiten, etc.

Das Inlining sollte prinzipiell nur fur Funktionen mit kleinem Funktionsrumpf eingesetzt werden.

Da der Code von Inline-Funktionen bei jedem ihrer Aufrufe benotigt wird, kommt die Programmie-

rung mehrfach im resultierenden Programm vor. Dies fuhrt zu langen Ubersetzungszeiten sowie großen

Executables. Also ist bei der Implementierung genau abzuwagen, welche Funktionen als inline dekla-

riert werden sollten. Zum Optimieren langer, geschachtelter Aufrufe von Inline-Funktionen braucht ein

Compiler oft unerwartet viel Speicher, was auch zu ubermaßig langen Ubersetzungszeiten fuhrt. Bei

besonders intensiven Inline-Optimierungen kann der Compiler auch an vordefinierte Grenzen stoßen,

so dass er dann das Inlining unterbricht. Mit diesem optimierten Code wird dann ein Funktionsaufruf

erzeugt und mit dem weiteren Inlining fortgefahren. Zur Uberprufung, ob die vorgegebenen Grenzen

uberschritten werden, bieten die meisten C++-Compiler das Winline-Flag an, das entsprechende War-

nungen ausgibt. Insbesondere die neueren Versionen des GNU-Compilers benennen sogar genau die

Parameter, die verandert werden mussen.

2.4.3 Aliasing

Bestehen in einem Programm mehrere Bezeichner oder Namen fur eine Speicheradresse, so werden

diese Ausrucke Aliase genannt [ASU86]. In C++ entstehen solche Mehrfach-Bezeichnungen fur Spei-

cheradressen durch Zeiger oder Referenzen, z.B. durch Speicherung, Zuweisung oder Ubergabe als

Parameter an Funktionen.

Um ein effizientes Programm zu erhalten, sind die Aliase vom Compiler an den Stellen aufzulosen, an

denen die referenzierten Speicherplatze den gleichen Wert enthalten. Dies sind also Falle, in denen uber

die Aliase nur gelesen und nicht geschrieben wird. Konnen diese Mehrfach-Referenzierungen vom Com-

piler nicht erkannt werden, so entsteht bei der Ausfuhrung des resultierenden Programms ein weniger

effizienter Code, denn das Datum im Speicher muss in beiden Fallen neu gelesen werden, obwohl es sich

nach dem ersten Lesen vielleicht noch im Cache befindet. So werden uberflussige Loads angestoßen,

welche bei haufigen Aufrufen die Performance merklich beeintrachtigen.

Der Compiler muss jedoch beim Erkennen und Auflosen der Aliase sehr konservativ vorgehen, um

keinen fehlerhaften Code zu erzeugen, der dann veranderte Daten nicht neu laden wurde. Aus der

grundsatzlichen Sicht konnte jedes Alias jeden Speicherbereich verandern, was aber keinerlei Opti-

mierungen zulassen wurde. Deshalb versucht der Compiler beim Ubersetzen mittels Datenflussanalyse

die Aliase zu bestimmen und, sofern sichergestellt ist, dass die Daten nicht verandert werden, diese

miteinander zu identifizieren.

2.4.4 Optimierung von Schleifen

Da bei gewohnlichen Programmen ein Großteil der Rechenzeit in Iterationsschleifen verbraucht wird,

ist die Optimierung von Schleifen unumganglich um performante Codes zu erzielen. Die generelle Ziel-

setzung ist dabei, die Zahl der auszufuhrenden Operationen zu reduzieren, sowie die benotigten Spei-

cherzugriffe moglichst cache-effizient zu gestalten. Nachfolgend findet sich eine Auswahl von wichtigen

Optimierungsmethoden, die je nach Problemstellung angewendet werden konnen [ASU86].

Neben der loop invariant code motion, bei der Codeteile, die sich nicht im Laufe der Schleifeniteration

verandern, vor oder nach die Schleife verlagert werden, werden dazu vor allem folgende Schleifentrans-

formationen vorgenommen.

16

Page 33: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 2. SPRACHGRUNDLAGEN UND PROGRAMMIERKONZEPTE

• Beim loop interchange, werden Iterationsschleifen vertauscht, um z.B. die Folge von Array-

durchlaufen zu andern. Dadurch kann in bestimmten Fallen eine bessere Nutzung der Caches

erreicht werden.

• Durch das Vereinigen von Schleifen (loop fusion) werden mehrere Schleifen in Eine zusammen-

gefasst, wodurch zusatzliche Kosten, wie Schleifenzahler oder Sprungbefehle, eingespart werden

konnen.

• Dem gegenuber kann auch das Aufspalten von Schleifen (loop fission), bei der eine Schleife in

mehrere aufgeteilt wird, zu einer besseren Ausnutzung der Caches fuhren bzw. eine Vektorisierung

erleichtern.

• Das cache blocking transformiert eine einfache in eine mehrfach geschachtelte Iterationsschlei-

fe, um so Arrays in Blockgroßen abarbeiten zu konnen, die der jeweiligen Große der Caches

entsprechen.

• Beim Entrollen von Schleifen (loop unrolling) werden die Schleifenrumpfe wiederholt ausgeschrie-

ben, um den Verwaltungsaufwand der Schleife zu verringern.

Wahrend manche Schleifentransformationen, wie etwa das Entrollen von Schleifen, durch den Com-

piler zur Ubersetzungszeit moglich sind, mussen andere oft explizit durch den Programmierer imple-

mentiert werden.

2.4.5 Kai C++-Compiler

Der Kai C++-Compiler wird gerade in Artikeln uber ET sehr haufig als derjenige Ubersetzer auf-

gefuhrt, mit dem die leistungsstarksten Programme erzielt wurden [BDQ97, LvG99]. Jedoch wurde

dieser Compiler von Intel ubernommen und die daraus entstandenen Versionen sind leider weniger

machtig.

Grundsatzlich funktionierte dieser Compiler u.a. wie ein Code-to-Code-Translator, der aus C++-

Programmen nach bestimmten High-Level-Optimierungen einen C-Code erzeugte, der dann mittels

gangigen C-Compilern ubersetzt werden konnte. Daraus ergaben sich sehr effiziente Programme, da

in C hardwarenahe Optimierungen leichter moglich sind als in C++, z.B. das Auflosen von Aliasen.

Außerdem konnten so gewisse Performance-Probleme von C++-Implementierungen leichter untersucht

werden, weil die Ergebnisse des Compilers als C-Code betrachtet werden konnten [BDQ97].

2.5 Zugrundeliegende Programmcodes

Prinzipiell konnen ET-Implementierungen in Verbindung mit den unterschiedlichsten Datenstruktu-

ren verwendet werden. Die klassische und weit verbreiteste Anwendung ist aber die Verwendung von

vektorbasierten Datenstrukturen.

Zum besseren Verstandnis und zur einheitlichen, kurzeren Darstellung der Programmiertechniken

die im Rahmen dieser Dissertation prasentiert werden, bauen die spateren Implementierungen auf

eine simple Vektorklasse auf. Eine minimale Version dieser Klasse zeigt Listing 2.1. Der Einfachheit

halber besteht diese Vektorklasse aus einem dynamischen Array vom Typ double. Stattdessen konnte

aber auch jeder andere Datentyp dafur gewahlt werden, der die gangigen mathematischen Operatoren

implementiert.

Neben dem Konstruktor, der ein dynamisches Array der angegebene Große erzeugt und dieses in-

itialisiert, hat die Klasse Vector auch einen Kopier-Konstruktor und einen Destruktor. Weiter zeigt die

Implementierung der Vektorklasse den uberladenen Zuweisungsoperator, um das Kopieren eines Vek-

tors mittels der mathematischen Notation a = b schreiben zu konnen. Durch die Methode size wird die

17

Page 34: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

2.5. ZUGRUNDELIEGENDE PROGRAMMCODES

Große des Arrays zuganglich gemacht. Die ubliche Zugriffsfunktion mittels des Operators operator[ ],

wird hier lediglich als Zuweisung der Komponenten eingefuhrt. Als eigentliche Zugriffsfunktion dient

eine give-Funktion, welche die i-te Komponente des Vektors zuruck gibt. Diese Methode verandert das

Objekt nicht und ist deswegen als konstant deklariert.

Listing 2.1: Vektordatenstruktur, Code-Grundlage fur weitere Implementierungen.

c l a s s Vector

p r i v a t e :

i n t s i z e ;

double ∗ data ;

5 pub l i c :

Vector ( i n t n , double i n i t = 0 . ) : s i z e ( n )

data = new double [ s i z e ] ;

f o r ( i n t i n d e x = 0 ; i ndex < s i z e ; ++index )

da ta [ i ndex ] = i n i t ;

10

˜Vector ( )

de l e t e [ ] da ta ;

Vector ( const Vector& vec )

15 a s s e r t ( s i z e == vec . s i z e ( ) ) ;

f o r ( i n t i n d e x = 0 ; i ndex < s i z e ; ++index )

da ta [ i ndex ] = vec . g i v e ( i ndex ) ;

Vector& ope ra to r= ( const Vector& vec )

20 a s s e r t ( s i z e == vec . s i z e ( ) ) ;

f o r ( i n t i n d e x = 0 ; i ndex < s i z e ; ++index )

da ta [ i ndex ] = vec . g i v e ( i ndex ) ;

r e t u r n (∗ t h i s ) ;

25 i n t s i z e ( ) const r e t u r n s i z e ;

double& ope ra to r [ ] ( i n t i n d e x )

r e t u r n data [ i ndex ] ;

double g i v e ( i n t i n d e x ) const

30 r e t u r n data [ i ndex ] ;

double ∗ d a t a p o i n t e r ( ) const r e t u r n data ;

;

Auf dieser einfachen Datenstruktur werden im Laufe dieser Arbeit verschiedene ET-Varianten auf-

gebaut. Falls fur die prasentierten Techniken Veranderungen dieser Vektorklasse notig sind, so werden

nur diese angedeutet. Die restlichen Variablen und Methoden konnen einfach ubernommen werden, um

eine vollstandige Implementierung zu erhalten. Die Codefragmente der nachfolgenden Kapitel sind dar-

auf ausgelegt, alle definierten Schnittstellen exakt anzugeben. Dabei wird besonders auf die Ubergabe

von Objekten als konstante Referenz geachtet, wo immer dies moglich und sinnvoll ist. Auch werden

die inline -Deklarationen von Funktionen angegeben, wenn diese notig sind.

18

Page 35: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 3. KLASSISCHE ET

3 Klassische ET

Der intuitive Ansatz, das Uberladen von Operatoren in C++ zu nutzen, fuhrt oft zu Programmen, wel-

che nicht die gewunschte Effizienz erreichen. Fur kleine Datenstrukturen wurde dies dennoch mit Erfolg

eingesetzt, z.B. beim STL-Typ complex [Str00]. Doch der Leistungsverlust, der durch die Einfuhrung

der mathematischen Schnittstellen entsteht, wird deutlich, wenn man die Performance großer, arrayba-

sierter Datenstrukturen betrachtet. Vergleicht man diese mit Implementierungen per Hand, bei denen

direkt mit Datenarrays gearbeitet wird, so verschlechtert sich die Performance der Codes mit steigender

Anzahl der Operationen enorm. Diese bekannte Problematik fuhrte dazu, dass dem Operatoruberladen

in C++ gerade in performance-relevanten Bereichen wie etwa dem Hochleistungsrechnen wenig Beach-

tung geschenkt wurde. Dies anderte sich jedoch mit der Einfuhrung der ET-Technik, die eine effiziente

Realisierung des Operatoruberladens ermoglicht.

Im Folgenden werden zunachst die Probleme des traditionellen Uberladens von Operatoren betrach-

tet. Darauf aufbauend werden die ET-Implementierungstechnik erlautert, zunachst mit einigen Be-

merkungen zu Veldhuizens erster prasentierter Version. Zusatzlich werden noch gangige Varianten der

ET-Programmierung und bekannte Bibliotheken dargestellt.

3.1 Das traditionelle Uberladen von Operatoren

Um das Problemfeld bezuglich des Uberladens von Operatoren ubersichtlich zu halten, beschrankt sich

die nachfolgende Diskussion auf das Uberladen des Plusoperators fur die Addition von Vektoren aus

Listing 2.1.

Eine Implementierungsvariante, die ein C++-Compiler gut und einfach optimieren kann, ist sicherlich

ein Programmcode im C-Stil. D.h. im Falle einer komponentenweisen Addition von Vektoren werden

die Summen in einer for-Schleife fur die Eintrage der Datenarrays berechnet.

Vector a (N) , b (N) , c (N) , d (N) ;

. . .

f o r ( i n t i =0; i<N; ++i )

a [ i ] = b . g i v e ( i )+ c . g i v e ( i ) + d . g i v e ( i ) ;

Hierbei wird insbesondere auch bei der Addition beliebig vieler Vektoren nur ein Schleifendurchlauf

benotigt und es werden keinerlei temporare Vektoren angelegt. Der Nachteil ist jedoch, dass diese Pro-

grammierweise gerade fur kompliziertere Datenstrukturen als Vektoren leicht zu Implementierungsfeh-

lern fuhrt. Solche aufwandigeren Datenstrukturen entstehen beispielsweise beim numerischen Losen

von partiellen Differentialgleichungen, bei denen die Diskretisierungssterne bestimmte Vektorkompo-

nenten verknupfen. Diese Komponenten sind im Diskretisierungsgebiet Nachbarn, doch auf Grund

entsprechender Nummerierungen liegen diese meist uber den Vektoren verstreut, siehe auch Kapitel

10.1. Wird eine solche Problemstellung im C-Stil programmiert, konnen leicht schwer aufzulosende

Zugriffsfehler entstehen.

3.1.1 Unmittelbare Auswertung im Operator

Aufbauend auf der Vektorklasse aus Listing 2.1 wollen wir entsprechend uberladene Operatoren ein-

fuhren, um einfache und intuitive mathematische Schnittstellen zu schaffen. Dadurch ist ein Anwender

19

Page 36: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

3.1. DAS TRADITIONELLE UBERLADEN VON OPERATOREN

nicht mehr gezwungen, die for-Schleife mit den komponentenweisen Operationen selbst zu implemen-

tieren. Der herkommliche Weg, die komponentenweise Summe zweier Vektoren mittels uberladenen

Operatoren zu realisieren, berechnet das Ergebnis der Addition unmittelbar im Operator. Dieser gibt

dann einen Ergebnisvektor zuruck, der die Summe der beiden Vektoren enthalt. Fur diese Berechnung

muss im Operator eine Iteration uber die Vektordaten durchlaufen werden, in welcher fur jede Kom-

ponente die Summe berechnet wird. Der Ergebnisvektor muss dabei jedesmal lokal erzeugt und bei der

Ruckgabe kopiert werden.

Vector ope ra to r+ ( const Vector& v1 , const Vector& v2 )

Vector tmp ( v1 . s i z e ( ) ) ;

f o r ( i n t i = 0 ; i < v1 . s i z e ( ) ; ++i )

tmp [ i ] = v1 [ i ] + v2 [ i ] ;

r e t u r n tmp ;

Um zu verstehen welche Probleme bei dieser Implementierung entstehen, wollen wir den folgenden

einfachen Anwendungscode betrachten. Ohne auf die Inhalte der Vektoren einzugehen, soll die Summe

von drei Vektoren berechnet und in einem vierten gespeichert werden.

a = b + c + d ;

Fur die Analyse wird die Arbeitsweise dieser Implementierung betrachtet, wobei wir annehmen, dass

alle unnotigen temporaren Objekte durch die Optimierung bereits eliminiert werden.

Zunachst wird die Summe von b und c berechnet, wofur innerhalb des Operators ein temporarer

Vektor erzeugt und mittels einer Iteration berechnet wird. Dieser temporare Vektor wird dann als Er-

gebnis der Operation in einer zweiten Addition mit d summiert. Dabei benotigen wir wiederum einen

temporaren Vektor und einen Schleifendurchlauf fur die Berechnung des Resultats. Das Ergebnis wird

dann an a zugewiesen, wofur wiederum eine Iteration durchgefuhrt wird. Insgesamt benotigen wir also

fur die Summation von drei Vektoren zwei temporare Vektoren, sowie drei Schleifendurchlaufe. Allge-

meiner braucht man mittels dieser Methode fur die Addition von n Vektoren n− 1 temporare Objekte

und n Iterationen. Wegen der wiederholten Allokation und dem anschließenden Loschen temporarer

Vektoren sowie den mehrfachen Schleifendurchlaufen sinkt die Performance dieser Implementierung

mit steigender Vektorgroße und steigender Operandenanzahl.

Betrachtet man Ausdrucke, bei denen der Vektor der linken Seite auch auf der rechten Seite auftritt

(z.B. a = a + b + c), kann ein temporarer Vektor und eine Iteration eingespart werden. Anstatt die

Addition von a explizit durchzufuhren, kann diese mit der Zuweisung in einem zusatzlichen operator+=

zusammengefasst werden (a += b + c). Diese Verbesserung kann aber lediglich in Sonderfallen ange-

wendet werden und lost nicht die eigentliche Problematik des traditionellen Operatoruberladens, d.h.

der sofortigen Berechnung der Operationen.

3.1.2 Ausdrucksbaume mittels abstrakter Klassen

Bei der Summation mehrerer Vektoren per Hand berechnet man jede Komponente des Ergebnisses

direkt aus der Summe der einzelnen Komponenten der Vektoren der rechten Seite, wobei keinerlei

temporare Vektoren und insgesamt nur eine einzige Iteration notig sind. Prinzipiell benutzt man fur die

Auswertung jeder Komponente den gesamten Ausdruck(sbaum) und wendet die jeweiligen Operationen

auf die i-ten Eintrage an. Um diesen Algorithmus zu implementieren muss man, anstatt die Operation

sofort auszufuhren, mittels der uberladenen Operatoren einen Ausdrucksbaum aufbauen, auf den die

Auswertung angewandt werden kann.

Diese Idee kann wie in Listing 3.1 implementiert werden, indem man eine abstrakte Klasse zur Kap-

selung der auftretenden Operationsklassen einfuhrt. Auf Grund der Vererbung muss die Komponenten-

funktion give jedoch als virtuell deklariert werden. Die Klassen, welche die Operationen beschreiben,

20

Page 37: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 3. KLASSISCHE ET

besitzen dann die implementierten Funktionen zum Berechnen der i-ten Komponente aus den gespei-

cherten Operanden. Da diese Funktionen nur einen sehr kleinen Funktionsrumpf haben und durch die

spate Bindung der virtuellen Funktionen zur Laufzeit ein großerer Overhead entsteht, resultieren aus

dieser Implementierung wiederum ineffiziente Programme. Genauer betrachtet, verschlechtert sich im

Allgemeinen die Performance bei dieser Programmierung noch im Vergleich zur vorher prasentierten

Berechnungsweise mittels temporarer Vektoren.

Listing 3.1: Implementierung eines Ausdrucksbaumes mittels abstrakter Klassen.

s t r u c t Exp r e s s i on

v i r t u a l double g i v e ( i n t i ) const = 0 ;

;

5 c l a s s Add : pub l i c Exp r e s s i on

p r i v a t e :

const Base∗ l ;

const Base∗ r ;

pub l i c :

10 Add( const Base∗ l , const Base∗ r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const

r e t u r n l −>g i v e ( i )+ r −>g i v e ( i ) ;

;

15 i n l i n e Add ope ra to r+(const Base& l , const Base& r )

r e t u r n Add(& l ,& r ) ;

c l a s s Vector : pub l i c Exp r e s s i on

. . .

20 ;

Allein der Aufbau eines Ausdrucksbaumes lost also nicht die Effizienzprobleme, die durch das Uber-

laden von Operatoren entstehen. Die Verwendung von virtuellen Funktionen mit einer spaten Bindung

zur Laufzeit und damit die fehlenden Inlining-Optimierungen fuhren zu keiner Leistungsverbesserung.

Eine effiziente Implementierung des Ausdrucksbaumes muss auf einer leistungsfahigen Technik basie-

ren, die alle Optimierungen zur Ubersetzungszeit ermoglicht.

3.2 Klassische ET-Implementierungen

Die Revolution bezuglich der großen Effizienzprobleme des Operatoruberladens in C++ wurde durch

die Einfuhrung von Expression Templates eingeleitet, zeitgleich prasentiert im Jahr 1995 von Veld-

huizen und Vandevoorde. Veldhuizen sah in seinem Artikel uber ET [Vel95] das Potenzial darin, die

Technik als performanten Ersatz fur Call-Back-Funktionen und als effizientes Operatoruberladen fur

arraybasierte Datenstrukturen einzusetzen. Dagegen prasentierte Vandevoorde ET als Variante, um

auf bestehende Klassen bzw. Container-Klassen (STL-Container valarray ) ein effizientes Uberladen von

mathematischen Operatoren aufzusetzen, und veroffentlichte die Idee in Online-Foren. Publiziert ist

die Implementierungsvariante unter anderem in [VJ03]. Die eigentliche Verbreitung der ET-Technik

fur das effiziente Berechnen numerischer Probleme leistete eine Veroffentlichung von Haney mit einer

Publikation in Computers in Physics [Han96], die im Wesentlichen auf den Artikel von Veldhuizen

aufbaut.

Wie der Name der Expression Templates (zu dt.: Ausdrucksschablonen, Ausdruckstemplates) bereits

verrat, werden bei dieser Technik Ausdrucke in templatisierte Objekte umgewandelt. Anders als bei Im-

plementierungen mit abstrakten Klassen und virtuellen Funktionen sind damit jederzeit die Typen der

Operationen bekannt. Dabei werden durch die uberladenen Operatoren wie vorher die Ausdrucksbaume

aufgebaut, in denen die Operationen als Template-Typen gespeichert sind. Die Auswertung findet erst

bei einer Zuweisung in einen neuen Vektor statt, bei der der Ausdruck dann komponentenweise in

21

Page 38: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

3.2. KLASSISCHE ET-IMPLEMENTIERUNGEN

einer Schleife berechnet wird. Ihre Performance erreichen ET dann durch die Inline-Optimierungen des

C++-Compilers, welche durch die in den Templates enthaltenen Typinformationen moglich sind.

3.2.1 ET-Programmierung via Veldhuizen

Wahrend die Auswertungen von Ausdrucken mittels ET nahezu vollstandig optimiert werden, konnen

beim Aufbau der Ausdrucksbaume jedoch unerwartet ineffiziente Programmcodes entstehen. Dies ist

meist dann der Fall, wenn dabei mehrfach Objekte kopiert und neu angelegt werden mussen.

Wie bereits erwahnt, veroffentlichte Veldhuizen in seinem Artikel die ET fur die Losung zweier Pro-

bleme in C++. Zum einen beschrieb er die Technik als Verbesserung zu den von C geerbten und

teilweise ineffizienten Call-Back Funktionen. Hierbei handelt es sich vorwiegend um kleine Objekte,

deren Kopien beim Aufbau der Expression keines großen Aufwands bedurfen. Bei der zweiten prasen-

tierten Problemstellung, dem effizienten Uberladen der Operatoren fur arraybasierte Datenstrukturen,

musste Veldhuizen jedoch darauf achten, dass die Vektordaten nicht unnotig kopiert werden, da dies bei

großen Vektoren einen ineffizienten Aufbau der Ausdrucksbaume zur Folge gehabt hatte. Um diese Ko-

pien zu vermeiden, werden in der damals prasentierten Implementierung nur die Zeiger auf die Arrays

abgespeichert, anstatt der gesamten Vektorklasse. Dadurch werden lediglich die Zeiger kopiert bzw. die

wiederum kleinen Objekte der gekapselten Operationen. Mit dieser Variante schafft Veldhuizen zwar

einen sehr effizienten Code, schrankt diese Verwendung von ET aber auf arraybasierte Datenstrukturen

ein.

Zum Aufbau eines Ausdrucksbaumes werden in der veroffentlichten Implementierung, die im Anhang

A der vorliegenden Arbeit vollstandig prasentiert ist, sogenannte Operationsklassen definiert, welche

die Funktionsweise einer Operation reprasentieren. Sie enthalten die zugrunde liegenden Operanden

als Membervariablen, deren Typen mittels Templates spezifiziert sind. Der Template-Mechanismus ge-

neriert dann wahrend der Ubersetzung des Programms die notigen Instantiierungen, abhangig von den

auftretenden Ausdrucken. Die Operanden in den Operationsklassen sind als volle Objekte abgespei-

chert, und deshalb werden beim Kopieren einer Expression auch die gespeicherten Objekte kopiert. Die

eingeschrankte Schnittstelle fur die verschiedenen Ausdrucke wird mittels einer sogenannte Wrapper-

Klasse eingefuhrt. Diese hat prinzipiell nur die Funktion die entstandenen Ausdrucke zu kapseln, um

die Parameter der Operatoren auf diesen templatisierten Typ zu spezifizieren.

Veldhuizen stand bei seiner Implementierung vor dem Problem, dass es zu dem Zeitpunkt keine

Moglichkeit gab, Member-Templates zu definieren. Deshalb musste er den Umweg uber eine abstrakte

Zuweisungsklasse gehen, um den Typ des Ausdrucks zu fassen und den Zuweisungsoperator zu reali-

sieren. Die dazu benotigten virtuellen Funktionen konnen bei den Optimierungen des Compilers nicht

durch Inlining optimiert werden. Doch dieser Aufruf einer virtuellen Funktion betrifft nur den ersten,

außersten Aufruf der Auswertung und hat somit keinen großen Einfluss auf die Performance.

3.2.2 Verbreitete ET-Implementierungen

Um einen Vergleich zu den neu entwickelten, in Kapitel 5 und 6 prasentierten Implementierungen zu

haben, wird im Folgenden eine gangige ET-Variante diskutiert. Diese stutzt sich auf die Programmie-

rungen von Vandevoorde [VJ03], sowie die bereits etwas einfachere Version in [AG05].

Listing 3.2 zeigt eine gangige Implementierung von ET, wie sie in einigen verbreiteten Bibliotheken

verwendet wird. Hierbei dient die Wrapper-Klasse wiederum als gemeinsame Schnittstelle fur die Ope-

rationen. Doch anstatt jedesmal das durch dem Wrapper gekapselte Objekt in den Operationsklassen

zu speichern, werden hier Referenzen auf die Objekte abgespeichert. Mittels der Funktion rep werden

die eigentlichen Operationen den Konstruktoren der Operationsklassen ubergeben. Dieses Abspeichern

von Referenzen verhindert das wiederholte Kopieren von Objekten, besonders von den Vektoren. Trotz-

dem, und darauf wird in Kapitel 4 genauer eingegangen, muss in der Wrapper-Klasse ein volles Objekt

abgespeichert werden. Zusatzlich zu dieser Implementierung enthalt Listing 3.2 die benotigten vier

22

Page 39: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 3. KLASSISCHE ET

uberladenen Versionen des Plusoperators, der Addition von zwei Vektoren, Vektor und Expression,

Expression und Vektor, sowie der Summe zweier Expressions. Die dabei entstehenden Operationsklas-

sen mussen wiederum in der Wrapper-Klasse gekapselt werden. Um die dazu notige Konstruktion in

den Operatoren zu vereinfachen, fuhrt man einen typedef ein, der den Typ der Addition definiert.

Listing 3.2: Gangige Implementierungsvariante der ET-Technik.

template <c l a s s E>

c l a s s Expr

E e ;

pub l i c :

5 Expr ( const E& e ) : e ( e )

double g i v e ( i n t i ) const r e t u r n e . g i v e ( i ) ;

const E& rep ( ) const r e t u r n e ;

;

s t r u c t Plus

10 s t a t i c double app l y ( double a , double b ) r e t u r n a + b ;

;

template <c l a s s L , c l a s s OpTag , c l a s s R>

c l a s s B ina r y Exp r

const L& l ; const R& r ;

15 pub l i c :

B i na r y Exp r ( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const

r e t u r n OpTag : : app l y ( l . g i v e ( i ) , r . g i v e ( i ) ) ;

20 ;

i n l i n e Expr<Bina ry Expr<Vector , Vector , Plus> >

ope ra to r+(const Vector& a , const Vector& b )

t ypede f Bina ry Expr<Vector , Vector , Plus> ExprT ;

r e t u r n Expr<ExprT>(ExprT ( a , b ) ) ;

25

template<c l a s s A>

i n l i n e Expr<Bina ry Expr<A, Vector , Plus> >

ope ra to r+(const Expr<A>& a , const Vector& b )

t ypede f Bina ry Expr<A, Vector , Plus> ExprT ;

30 r e t u r n Expr<ExprT>(ExprT ( a . r ep ( ) , b ) ) ;

template<c l a s s A>

i n l i n e Expr<Bina ry Expr<Vector ,A, Plus> >

ope ra to r+(const Vector& a , const Expr<A>& b)

35 t ypede f Bina ry Expr<Vector ,A, Plus> ExprT ;

r e t u r n Expr<ExprT>(ExprT ( a , b . r ep ( ) ) ) ;

template<c l a s s A, c l a s s B>

i n l i n e Expr<Bina ry Expr<A,B, Plus> >

40 ope ra to r+(const Expr<A>& a , const Expr<B>& b)

t ypede f Bina ry Expr<A,B, Plus> ExprT ;

r e t u r n Expr<ExprT>(ExprT ( a . r ep ( ) , b . r ep ( ) ) ) ;

Wie an diesen Programmcodes erkennbar ist, wird die Implementierung von ET schnell komplex und

aufwandig. Dabei kann die Programmierung der sich ahnelnden uberladenen Versionen der Operatoren

leicht zu komplizierten Fehlermeldungen fuhren. Daruber hinaus sind in den richtigen Klassen ganze

Objekte bzw. nur Referenzen abzuspeichern, da sonst bereits Objekte geloscht sind und damit nicht

mehr existieren, obwohl sie im Weiteren noch referenziert werden (siehe Abschnitt 4.3).

Prinzipiell kann diese Implementierung dadurch abgewandelt werden, indem die Wrapper-Klasse

Expr weggelassen, und direkt mit den Typen Binary Expr als spezifische Schnittstelle gearbeitet wird. Da-

durch verkomplizieren sich die Operatoren jedoch noch mehr, denn die Expressions besitzen somit drei

Template-Typen. Hier als Beispiel eine Version des Plusoperators mit der Operationsklasse Binary Expr

23

Page 40: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

3.3. BEKANNTE ET BIBLIOTHEKEN

als Schnittstelle.

Listing 3.3: Variante eines uberladenen Operators ohne explizite Wrapper-Klasse.

template<c l a s s A1 , c l a s s A2 , c l a s s OpA , c l a s s B1 , c l a s s B2 , c l a s s OpB>

Bina ry Expr<Binary Exp<A1 , A2 ,OpA>, B ina ry Expr<B1 , B2 ,OpB>,Plus>

ope ra to r+(const Binary Exp<A1 , A2 ,OpA>& a ,

const Bina ry Expr<B1 ,B2 ,OpB>& b)

r e t u r n

Bina ry Expr<Binary Exp<A1 , A2 ,OpA>,

B ina ry Expr<B1 ,B2 ,OpB>, Plus >(a , b ) ;

Daruber hinaus mussen fur unare Operationen weitere Operationsklassen definiert werden. Da dann

drei mogliche Typen fur die Parameter der zu uberladenden Operatoren zur Verfugung stehen, sind

folglich je neun Versionen zu implementieren.

Dennoch existieren einfachere und kurzere Programmierungvarianten der ET-Technik, wie in Kapitel

5.3 dargestellt. Hier wird dann fur jeden Operator nur noch je eine uberladene Version eines Operators

benotigt.

3.3 Bekannte ET Bibliotheken

Nach der Einfuhrung von ET durch Veldhuizen und Vandevoorde, war es vor allem der Artikel von

Haney [Han96], welcher die ET-Implementierungstechnik fur wissenschaftliche Fragestellungen bekannt

machte. Daraufhin wurden einige effiziente Bibliotheken mittels ET entwickelt, die nachfolgend zusam-

mengefasst werden.

PETE

Die Portable Expression Templates Engine (PETE) dient dazu, Entwickler bei der Implementierung

von ET zu unterstutzen. Mittels der Bibliothek konnen die notigen Codes generiert werden, um die

vielen ahnlichen Versionen der uberladenen Operatoren nicht per Hand implementieren zu mussen.

Dazu werden die Blatter und Operationen des Ausdrucksbaumes angegeben, anhand derer – unter

anderem auch fur STL-Container – ET-Implementierungen erzeugt werden [HCKS98].

Blitz++

Die Software-Bibliothek Blitz++ implementiert effiziente Operationen fur Vektoren, mehrdimensionale

Arrays, sowie Matrizen. Bei der Entwicklung dieser Bibliothek wurden viele Konzepte der generischen

Programmierung mittels Templates eingefuhrt und angewandt. Besonders wichtig war den Programmie-

rern dabei, die Performance von FORTRAN Implementierungen zu erreichen oder sogar zu ubertreffen

[Vel01].

MTL, MET, TVMET

Die Matrix Template Library (MTL) und Matrix Expression Templates (MET) sind effiziente linea-

re Algebra Bibliotheken. Die Intention hierbei war, den wissenschaftlichen Softwareentwicklern leis-

tungsstarke und benutzerfreundliche Implementierungen fur die immer wieder benotigten Vektor- und

Matrix-Berechnungen zur Verfugung zu stellen [SL01, Mas01]. Wie wir spater noch genauer sehen

werden, erreichen normale ET bei kleinen Datenstrukturen nicht die gewunschte Performance von C-

Implementierungen. Aus diesem Grund wurde fur kleine Vektoren die Tiny Vector Matrix Expression

Templates (TVMET) eingefuhrt [Pet03]. Dabei kann durch die Angabe der Vektorgroße zur Uberset-

zungszeit durch Templates ein effizienterer Programmcode erreicht werden.

24

Page 41: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 3. KLASSISCHE ET

uBLAS

uBLAS [WK02] ist eine C++-Bibliothek, die mittels ET leistungsstarke Berechnungen und Losungs-

algorithmen der linearen Algebra durchfuhrt, die bereits in der FORTRAN-Bibliothek BLAS implemen-

tiert wurden [LHKK79]. Diese Entwicklung aus der C++-Bibliothek BOOST [AS01] bietet ebenfalls

ein effizientes Uberladen der gangigen Vektor- und Matrix-Operationen an. Daruber hinaus sind auch

verschiedene Normen oder unterschiedliche Typen von Matrizen, sowie effiziente Loser implementiert.

POOMA

Die spezialisierte Anwendung der ET-Technik fur die Losung partieller Differentialgleichungen wurde

in der Bibliothek POOMA (Parallel Object-Oriented Methods and Appliations) realisiert. Dabei wer-

den sehr spezifische Schnittstellen angeboten, um Diskretisierungen mittels der Finiten Differenzen

Methode sehr einfach und intuitiv programmieren zu konnen. Die zugrunde liegenden Datenarrays

sind auf das parallele Losen der numerischen Probleme ausgelegt. POOMA bietet dazu speziell die

zwei Hauptdatentypen Fields und Particles [Rum96].

ExPDE

Eine effiziente, benutzerfreundliche Bibliothek zum Losen von partiellen Differentialgleichungen mit-

tels der Finiten Elemente Methode wurde in ExPDE (Expression Templates for Partial Differential

Equations) implementiert [Pfl01]. Aufbauend auf ET unterstutzt die Bibliothek das einfache Program-

mieren von Differentialoperatoren auf verschiedenen Diskretisierungsgittern. Eine sehr intuitive und

problemnahe Formulierung der zugrunde liegenden partiellen Differentialgleichungen ermoglicht eine

schnelle und einfache Implementierung, wobei besonders auch die Programmierung passender Loser

unterstutzt wird. Durch Compiler-Switches kann automatisch zwischen einer seriellen oder parallelen

Version gewahlt werden.

Weitere ET Bibliotheken

Daruber hinaus gibt es noch eine Reihe weiterer C++-Bibliotheken, deren Implementierungen auf ET

basieren. Obige Darstellung konzentriert sich aber auf die Auswahl der fur die Anwendungen dieser

Dissertation wichtigen Programme. Prinzipiell finden solche ET-Bibliotheken gerade wegen ihrer effizi-

enten mathematischen Schnittstellen und ihrer FORTRAN-ahnlichen Performance große Anwendung

im wissenschaftlichen Rechnen und der numerischen Simulation. Daneben werden aber auch weiterhin

neue ET-basierende Programme entwickelt, die haufig aus komplizierten und nicht optimalen Imple-

mentierungen bestehen.

Deshalb wird im Weiteren die Technik der ET genauer untersucht und einfachere Varianten der

Methoden prasentiert, um das effiziente Uberladen von Operatoren in C++ intuitiver und kurzer

programmieren zu konnen.

25

Page 42: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

3.3. BEKANNTE ET BIBLIOTHEKEN

26

Page 43: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 4. ANALYSE VON ET UND VERBESSERUNGSANSATZE

4 Analyse von ET-Programmen und

Verbesserungsansatze

Nach der Einfuhrung in die ET-Technik in Abschnitt 3.2.2 und der Zusammenfassung der wichtigsten

Bibliotheken, die auf dieser Methode basieren (Abschnitt 3.3), werden im vorliegenden Kapitel die

Wirkungsweise sowie die einzelnen Bestandteile solcher Implementierungen analysiert. Dazu werden

im Folgenden die ET-Programmierungen aus Abschnitt 3.2.2 zugrunde gelegt, welche aufbauend auf

der in Abschnitt 2.5 prasentierten Vektorklasse die Operatoren uberladt.

4.1 Effizienz der ET-Technik

Die Performance von ET kann nur durch entsprechende Optimierungen des C++-Compilers erreicht

werden. Anders als bei der zunachst prasentierten Programmierung von Ausdrucksbaumen mittels

abstrakten Klassen und virtuellen Funktionen, sind die Typen aller ET-Objekte bereits zur Uberset-

zungszeit bekannt. Deshalb kann der Compiler die Inlining-Optimierungen durchfuhren und so den

großen Overhead der wiederholten Aufrufe von kleinen Funktionen vermeiden. Zur genauen Analyse

dient als einfaches Beispiel die Optimierung der Vektortriade

a = b + c ∗ d ;

mit komponentenweiser Addition und Multiplikation. Die entsprechenden Operationsklassen und uber-

ladenen Operatoren aus Abschnitt 3.2.2 dienen nun dazu, die Vektortriade in einen Template-Aus-

drucksbaum zu kapseln. Dabei besitzt das ET-Objekt der rechten Seite (bezeichnet mit expr) den

Template-Typ:

Bina ry Expr<Vector ,

B ina ry Expr<Vector , Vector , Times> >, Plus> > expr

Dieses Template-Objekt expr dient als Ubergabe fur den Zuweisungsoperator der Vektorklasse. Dabei

wird wahrend der Auswertung fur jede Komponente die Funktion give aufgerufen, deren geschachtelten

Aufrufe mittels des Inlining aufgelost werden konnen. Diese sukzessive Inline-Optimierungen werden

im nachfolgenden Code vereinfacht dargestellt.

expr . g i v e ( i )

== Plus : : app l y ( expr . l . g i v e ( i ) , expr . r . g i v e ( i ) )

== expr . l . g i v e ( i ) + expr . r . g i v e ( i )

== expr . l . g i v e ( i ) + Times : : app l y ( expr . r . l . g i v e ( i ) , expr . r . r . g i v e ( i ) )

== expr . l . g i v e ( i ) + expr . r . l . g i v e ( i ) ∗ expr . r . r . g i v e ( i )

== b [ i ] + c [ i ] ∗ d [ i ]

Durch dieses sukzessive Auflosen des Inlinings kann der Compiler prinzipiell die verschachtelten

Template-Konstrukte auf den Programmcode reduzieren, den man per Hand ohne uberladene Opera-

toren schreiben wurde. Dies stellt lediglich eine exemplarische Folge der Optimierungen des Compilers

dar und soll nur zur einfachen Anschauung dienen.

Da die uberladenen Operatoren die Template-Objekte des Ausdrucksbaumes aufbauen, entsteht vor

allem fur kleine Vektoren ein durchaus bemerkbarer Overhead im Vergleich zur Implementierung per

Hand. Doch fur Vektoren, die nicht mehr in den Cache passen, beeintrachtigt das Bilden der Opera-

tionsobjekte die Performance nicht mehr wesentlich. Hier uberwiegen dann die Loads und Stores, die

27

Page 44: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

4.2. KOMPONENTEN VON ET

benotigt werden, um die Daten in und aus den Cache zu bringen. In Kapitel 6.1.1 wird erortert, dass

selbst diese gangigen ET-Implementierungen durchaus noch Optimierungspotenzial besitzen. Dies be-

trifft hauptsachlich ein unvollstandiges Auflosen des Zeiger-Aliasing, was sich aber nur bei Ausdrucken

bemerkbar macht, in denen Vektoren wiederholt auftreten.

Nachfolgend werden die verschiedenen Bestandteile von ET-Programmen untersucht, sowie deren

Funktionsumfang und Nutzen zusammengestellt.

4.2 Komponenten von ET

Naturlich konnen die Implementierungen von ET beliebig komplex werden, so dass die Programmie-

rinhalte weit uber die hier aufgefuhrten Konzepte hinausgehen konnen. Im Wesentlichen teilt sich ein

ET-Code in vier untereinander verknupfte Einheiten auf, die jeder Variante zugrunde liegen:

• Eine oder mehrere Wrapper-Klassen, zum Erstellen von Schnittstellen, die nicht von den zugrunde

liegenden Ausdrucken abhangen (sie bilden einen Teil der Nicht-Terminale im Ausdrucksbaum),

• Datenstruktur(en) mit entsprechenden Zugriffs- und Zuweisungsmethoden bzw. Objekte funda-

mentaler Datentypen (diese Objekte bilden die Terminale),

• Operationsklassen, welche als Darstellung der jeweiligen Operation die Operanden speichern und

die Operation(en) durchfuhren (Non-Terminale im Ausdrucksbaum) und

• Creator Funktionen und die uberladenen Operatoren zum benutzerfreundlichen Aufbau der ET-

Objekte.

Im Folgenden werden diese einzelnen Komponenten untersucht und deren spezifischen Eigenschaften

herausgearbeitet. Dabei werden zur besseren Anschauung die Expressions als Ausdrucksbaume mit

Blattern und Knoten bzw. mit Terminalen und Nicht-Terminalen bezeichnet.

4.2.1 Wrapper-Klassen

Um keine allgemeinen Template-Parameter in den uberladenen Operatoren einsetzen zu mussen, be-

notigt man eine oder zumindest eine beschrankte Anzahl von Schnittstellen, welche die verschiedenen

Ausdrucke kapseln, die mittels der implementierten Operatoren gebildet werden konnen. Dazu wer-

den sog. Wrapper- oder Handle-Klasse verwendet, die lediglich dazu dienen, den Zugriff auf andere

Klasse zu kontrollieren oder um die Schnittstellen von bestehenden Klassen entsprechend anzupassen

[Str00]. Wahrend die Implementierung von Veldhuizen mit einem Wrapper auskommt, kann man in den

weiteren Entwicklungen von ET sehen, dass auch mehrere solcher Klassen zur Kapselung eingesetzt

werden konnen. Zum Beispiel kann es durchaus sinnvoll sein, bei Implementierungen fur Vektor- und

Matrix-Berechnungen separate Wrapper-Klassen fur Vektor- bzw. Matrix-Expressions einzufuhren, um

jederzeit sicherzustellen, welcher Art das Resultat sein wird. Dadurch kann eine fehlerhafte Verwendung

der ET-Implementierung vermieden werden.

Die Wrapper-Klassen werden prinzipiell nur als Schnittstelle fur die Operatoren benotigt, d.h. beim

Erzeugen eines neuen Knotens, mussen die abgespeicherten Operanden nicht mehr gekapselt sein. Der

Wrapper wird also nur als außerste Schicht des Ausdrucksbaumes gebraucht und im Inneren kann man

– wie in Listing 3.2.2 – darauf verzichten. Es wurde also fur die Programmierung von ET genugen,

den Wrapper immer um die Wurzel des Ausdrucksbaumes herumzubauen und bei der Abspeicherung

in Operationsklassen diese Kapselung wieder wegzulassen. Innerhalb des Baumes werden dann direkt

die Aste angesprochen, ohne Zwischeninstanz.

Abbildung 4.1 stellt exemplarisch die Konstruktion des Ausdrucksbaumes zur Vektortriade (b + c ∗ d)

dar. Hierbei wird die Wrapper-Klasse, die die Multiplikation (b ∗ c) der linken Seite umfasst, im Aus-

drucksbaum der rechten Seite weggelassen.

28

Page 45: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 4. ANALYSE VON ET UND VERBESSERUNGSANSATZE

Abbildung 4.1: Die graphische Darstellung des Ausdrucksbaumes zur Vektortriade, wobei die

Wrapper-Klassen der Operanden weggelassen werden.

Fur diese Speicherung der Operanden ohne Wrapper-Klasse werden zusatzliche Methoden definiert,

die das gekapselte Objekt zuruckgeben (Funktion rep in Listing 4.1). Dieses enthalt bereits die komplet-

te Information bzgl. des Ausdrucksbaumes und genugt als gespeichertes Element. Diese Verkurzung

des Ausdrucksbaumes bringt auch fur die anstehenden Inline-Optimierungen Vorteile, da weniger ge-

schachtelte Aufrufe durch den Compiler aufgelost werden mussen.

Listing 4.1: Methode zum Abspeichern der Operanden ohne Wrapper.

template <c l a s s E>

c l a s s Expr

p r i v a t e :

const E exp r ;

pub l i c :

Expr ( const E& expr ) : e x p r ( expr )

double g i v e ( i n t i ) const

e x p r . g i v e ( i ) ;

const Expr& rep ( ) const r e t u r n e x p r ;

;

Eine weitere Moglichkeit die Wrapper-Kapselung im Inneren des Ausdrucksbaumes wegzulassen,

besteht in der Anwendung der CRTP-Technik, siehe Abschnitt 2.3.6. Dabei werden die Operations-

klassen von der Wrapper-Klasse mit ihrem eigenen Klassentyp als Template-Parameter abgeleitet.

Dadurch kann ein Objekt der Basisklasse durch eine explizit durchgefuhrte Konvertierung in ein Ob-

jekt des abgeleiteten Typs umgewandelt werden. Weil hierbei der Typ der Ableitung bekannt ist, kann

man Methodenaufrufe zur Auswertung durch einen static cast an das entsprechende abgeleitete Objekt

weiterreichen. Insgesamt erspart man sich durch die Verwendung der CRTP-Technik die zusatzliche

Speicherung eines Objektes der Wrapperklasse. Außerdem mussen die Objekte nicht mehr explizit

durch die Wrapper-Klasse gekapselt werden, weil jede abgeleitete Klasse bereits durch die CRTP-

Technik vom Typ der Wrapper-Klasse ist. Dies wird in Kapitel 5 dazu genutzt werden, eine einfache

Implementierung der Operatoren zu erreichen.

template <c l a s s E>

s t r u c t Expr ;

template <c l a s s A, c l a s s B, c l a s s Op>

c l a s s B ina r y Exp r : pub l i c Expr<Bina ry Expr<A,B,Op> > . . . ;

Somit kann die Wrapper-Klasse – im Prinzip – als leere Klasse definiert werden. Dann mussten jedoch

vor jedem Aufruf von Methoden oder vor jedem Ubergeben an eine Methode die Objekte entsprechend

in ihren abgeleiteten Typ umwandelt werden. Diese Umwandlungen werden vom Compiler zwar wie

29

Page 46: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

4.2. KOMPONENTEN VON ET

gewunscht optimiert, doch wird der Programmcode durch die vielen expliziten Typumwandlungen

unnotig kompliziert.

Deshalb werden in den prasentierten Weiterentwicklungen spezielle Konvertierungs-Operatoren in

der Wrapper-Klasse definiert, um die entsprechenden Typumwandlungen vom Compiler automatisch

durchfuhren zu lassen (Listing 4.2). Solche benutzerdefinierten Typumwandlungen sollten in Imple-

mentierungen nur sehr gezielt eingesetzt werden, um unnotige Fehlerquellen in den Programmen zu

vermeiden. Im Falle der Wrapper-Klasse macht dies jedoch Sinn, denn es soll nur die explizite Um-

formung des Basisklassen-Typs in den Typ der abgeleiteten Klasse automatisch durch den Compiler

durchgefuhrt werden. Da ein Ausdruck wahrend der Auswertung meist nicht verandert werden soll,

sondern lediglich mehrere const-Funktionsaufrufe ausgefuhrt werden, genugt es in den meisten Fallen,

einen Konvertierungsoperator fur die Umwandlung in eine konstante Referenz zu definieren. Bei der

Implementierung ist aber darauf zu achten, dass der neu eingefuhrte Cast nicht wieder einen static cast

auf die konstante Referenz aufruft, da dies zu einer Endlos-Rekursion fuhren kann. Stattdessen sollte

man intern einen Cast auf den Zeigern auf die Objekte durchfuhren und das umgewandelte Ergebnis

dereferenzieren. Listing 4.2 zeigt eine nach mit diesen Vorgaben implementierte Wrapper-Klasse.

Listing 4.2: Wrapper-Klasse mit explizitem Konvertierungsoperator.

template <c l a s s E>

s t r u c t Expr

ope ra to r const Expr& ( ) const

r e t u r n ∗ s t a t i c c a s t <const E∗>( t h i s ) ;

double g i v e ( i n t i ) const

s t a t i c c a s t <const E&>(∗ t h i s ) . g i v e ( i ) ;

;

Zusammenfassend kann man die notigen Funktionen der Wrapper-Klasse wie folgt definieren. Die

Wrapper-Klasse

• ist eine Handle-Klasse und dient nur als Schnittstelle,

• ubergibt Methodenaufrufe an die entsprechenden Objekte, und

• wird nur als außerste Schicht der Ausdrucke benotigt.

Prinzipiell kann man auf die Einfuhrung von Wrapper-Klassen ganz verzichten, wenn die Operatoren

ohne diese explizite Schnittstelle uberladen werden. Dies kann durch das Uberladen mittels allgemeiner

Template-Typen erfolgen, wobei dies leicht zu unerwunschten Mehrdeutigkeiten fuhren kann, siehe dazu

auch Kapitel 5.2. Daneben konnen auch die Operationsklassen als Wrapper benutzt werden (Kapitel

4.2.3), was aber die Anzahl der uberladenen Versionen je Operator erhoht, da meist mehr als eine

Operationsklasse existiert, siehe Abschnitt 3.2.2.

4.2.2 Grunddatenstrukturen

Die Grunddatenstrukturen beschreiben die Blatter (Terminale) in einem Ausdrucksbaum, was ahn-

lich bereits in der Bibliothek PETE zum Erzeugen der ET-Codes so gehandhabt wurde [HCKS98].

Allgemein betrachtet konnen ET fur ganz unterschiedliche Datenstrukturen verwendet werden. Im

Folgenden werden verschiedenartige Varianten diskutiert, sowie die dazu notigen Anderungen in der

Implementierung erlautert.

In seinem bereits erwahnten Artikel uber ET betrachtete Veldhuizen [Vel95] die Verwendung der

Technik als Ersatz fur Call-Back-Funktionen und zum effizienten Uberladen von Operatoren von array-

basierten Datenstrukturen. Call-Back-Funktionen, die Ubergabe von Funktionszeigern als Parameter,

30

Page 47: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 4. ANALYSE VON ET UND VERBESSERUNGSANSATZE

sind eine Technik die von C ubernommen wurde. Dadurch war es unter anderem moglich, Sortieralgo-

rithmen mit benutzerdefinierter Sortierung oder numerische Integrationen fur anwendereigene Funktio-

nen zu definieren. Die Effizienzprobleme von Call-Back-Funktionen entstehen hauptsachlich durch den

wiederholten, nicht optimierbaren Aufruf von Funktionen mit faktisch kleinem Funktionsrumpf. Bei

Implementierungen mittels ET konnen durch entsprechend uberladene Operatoren ebenfalls Sortiervor-

schriften und Funktionen erfasst werden. Die zugrunde liegenden Datenstrukturen sind hierbei Klassen

ohne großen Dateninhalt, sie dienen lediglich als Platzhalter fur die Erstellung der Funktionsformeln.

Stattdessen wird die damit konstruierte ET-Formel fur verschiedene eingesetzte Daten ausgewertet.

Das nachfolgende Listing zeigt beispielsweise den Aufruf fur eine numerische Integration der Funktion

3x2 +√

x + 1−2 auf dem Intervall [0, 3]. Zur approximativen Berechnung des Integrals muss die Funk-

tion an bestimmten Stutzstellen ausgewertet werden. Doch die auftretenden ET-Ausdrucke selbst sind

nur kleine Objekte, die keinen großen Kopieraufwand erzeugen.

double r e s u l t =

i n t e g r a t e ( 0 , 3 ,

3 ∗ x (2) + Sqr t ( x (1) + 1 ) − 2 ) ;

Dem entgegen steht die Verwendung von ET fur Vektorberechnungen, bei der im Allgemeinen mit

großen Objekten gearbeitet werden muss. Hierbei werden Datenstrukturen mit dynamischen Arrays

als große Objekte bezeichnet, obwohl intern eigentlich nur der Zeiger zur Klasse gehort. Beim Erstellen

einer tiefen Kopie wird auch das dynamische Datenfeld kopiert. D.h. es ist darauf zu achten, dass

bei der Programmierung zum Aufbau des Ausdrucksbaumes diese Objekte nicht oder zumindest nicht

unnotig kopiert werden. Deshalb muss speziell bei Vektoren als Operanden sichergestellt sein, dass

diese nur als Referenzen und nicht als volle Objekte abgespeichert werden.

Prinzipiell konnen Implementierungen mittels ET aber fur Datenstrukturen beliebiger Große an-

gewendet werden. Wie wir in Kapitel 6.1.1 sehen werden, entsteht aber bei Zeigervariablen in den

Basis-Datenstrukturen ein Aliasing, das bei wiederholtem Auftreten in einer Expression nicht auf-

gelost werden kann. Deshalb sollten Zeiger und dynamische Arrays – wo moglich – vermieden werden,

auch wenn spater Methoden prasentiert werden die dazu dienen, den Compiler dabei zu unterstutzen

diese Aliasing-Probleme aufzulosen (siehe Kapitel 6.2).

Um in Kombination mit einer ET-Programmierung zu funktionieren, mussen Teile der Datenstruktur

entsprechend angepasst werden. Da bei herkommlichen Implementierungen die Basis-Datenstrukturen

nicht von der Wrapper-Klasse gekapselt sind, mussen fur alle Schnittstellen zusatzliche uberladene

Versionen eingefuhrt werden. Als Vereinfachung konnen diese wiederkehrenden verschiedenen Parame-

terlisten mittels Makros einmal allgemein definiert werden, und diese Varianten werden dann durch

den Precompiler erzeugt. Zum einen fuhren Makros aber zu schwerer verstandlichen und wartbaren

Programmcodes. Zum anderen kann man daraus resultierende Fehlermeldungen schwieriger nachvoll-

ziehen, da sie sich auf die bereits expandierten Makros beziehen, nicht auf den ursprunglichen Code.

Eine kurzere und verstandlichere Implementierung erhalt man, indem die zugrunde liegenden Da-

tenstrukturen, wie bereits bei den Wrapper-Klassen angedeutet, ebenfalls als Ableitung vom Wrapper

definiert werden. Um diese Kapselung nicht explizit durchfuhren zu mussen, kann an dieser Stelle

die CRTP-Technik angewandt werden. Die Datenstruktur erbt von der Wrapper-Klasse mit dem ei-

genen Typ als Template-Parameter. Dadurch kann automatisch jeder Vector in den entsprechenden

Expr<Vector> konvertiert werden. Als Resultat benotigt man keine zusatzlichen uberladenen Versionen

der Operatoren fur die Grunddatentypen mehr, da diese nun als Expressions behandelt werden und so

in die bereits definierten Operatoren passen.

c l a s s Vector : pub l i c Expr<Vector >

. . .

;

Als Verbindung der Grunddatenstruktur(en) und den entstehenden ET-Ausdrucken muss eine Aus-

wertung der Ausdrucksbaume implementiert werden. Dies geschieht meistens in einem Zuweisungsope-

31

Page 48: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

4.2. KOMPONENTEN VON ET

rator operator=, kann aber auch in einer anderen (Member-)Funktion des Ergebnisdatentyps geschehen.

Die entsprechende templatisierte Methode hat einen Parameter vom Typ Expr<E>, dessen Auswer-

tungsfunktion aufgerufen wird. Arbeiten die Wrapper-Klassen mit CRTP und besitzen selbst keine

Auswertungsfunktion, so mussen die durch Wrapper gekapselten Objekte vor dem Aufruf noch in den

entsprechenden abgeleiteten Typ E umgewandelt werden.

c l a s s Vector : pub l i c Expr<Vector >

. . .

template <c l a s s E>

vo id ope ra to r=(const Expr<E>& e )

f o r ( i n t i = 0 ; i < s i z e ; ++i )

da ta [ i ] = s t a t i c c a s t <const E&>(e ) . g i v e ( i ) ;

;

Zusatzlich wird noch die Anwendung von ET fur bereits bestehende Datenstrukturen diskutiert,

ohne dabei die Implementierung der existierenden Klasse verandern zu mussen. Als erste Moglichkeit

kann man eine Handle-Klasse definieren, die von der bestehenden Datenstruktur erbt. Dadurch wird die

volle Funktionalitat auf die neue Klasse ubertragen [Fur97]. Es mussen lediglich eigene Konstruktoren,

Kopier-Konstruktoren und Zuweisungs- bzw. Zugriffsoperatoren eingefuhrt werden, welche die entspre-

chenden Daten an die eigentliche Klasse weiterreichen. Auf diese so abgeleiteten Handle-Klassen kann

dann eine Implementierung mittels ET aufgebaut werden. In einer Anwendung wird dann naturlich

nur die neue Klasse verwendet, die sich aber in der Funktionalitat nicht von der ursprunglichen unter-

scheidet und mit einer ET-Programmierung funktioniert.

s t r u c t Vector : pub l i c s t d : : v ec to r <double >, pub l i c Expr<Vector >

Vector ( i n t s i z e ) : s t d : : v ec to r <double >( s i z e )

. . .

;

Soll jedoch weiterhin mit der existierenden Klasse gearbeitet werden, so besteht die Moglichkeit, in

der Wrapper-Klasse des ET-Programms einen Konvertierungsoperator einzufuhren, der ein Expression-

Objekt in den Typ der bestehenden Klasse umwandelt. Dazu benotigt man aber intern ein tem-

porares Objekt bei der Auswertung, sowie einen bereits implementierten Kopier-Konstruktor bzw.

Zuweisungsoperator in der Basis-Datenstruktur. Daruber hinaus sind die Operatoren wieder fur alle

Kombinationen zwischen Ausdrucken und der bestehenden Grunddatenstruktur zu defnieren. Doch

mit der entsprechenden ET-Implementierung konnen dann fur die bestehende Datenstruktur wie

ublich Ausdrucksbaume aufgebaut und berechnet werden. Das nachfolgende Listing zeigt beispiels-

weise eine entsprechende Implementierung der Wrapper-Klasse fur die Verwendung mit STL-Vektoren

(std :: vector<double>).

template<c l a s s A>

s t r u c t Expr

ope ra to r const A& () const

r e t u r n ∗ s t a t i c c a s t <const A∗>( t h i s ) ;

ope ra to r s t d : : v ec to r <double> ( ) const

const A& a (∗ t h i s ) ;

i n t s i z e = a . s i z e ( ) ;

s t d : : v ec to r <double> tmp ( s i z e ) ;

f o r ( i n t i =0; i < s i z e ; ++i )

tmp [ i ] = a [ i ] ;

r e t u r n tmp ;

;

So analysiert ergibt eine große Menge von Datenstrukturen, bei denen es sinnvoll ist die Operatoren

oder entsprechenden Funktionen mittels ET-Implementierungen zu realsisieren.

32

Page 49: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 4. ANALYSE VON ET UND VERBESSERUNGSANSATZE

4.2.3 Operationsklassen

Durch die Operationsklassen werden die anwendbaren Operationen sowie die jeweiligen Operanden

gekapselt. Der Typ der Operanden – und das fuhrt wie bereits erwahnt zur Effizienz der ET – wird

in den Template-Parametern der Operationsklassen gespeichert, ist damit also zur Ubersetzungszeit

bekannt. In C++ gibt es nur unare und binare Operatoren, die uberladen werden konnen. Doch prinzi-

piell kann es auch sinnvoll sein, Operationen mittels Funktionen zu definieren, die auch drei oder mehr

Operanden kombinieren konnen (siehe Abschnitt 12.2).

Die Operationsklassen beschreiben die Knoten, also Nicht-Terminale im Ausdrucksbaum, an dem

ein oder mehrere Terminale oder Nicht-Terminale hangen. Neben dem Konstruktoraufruf mit den

jeweiligen Operanden, enthalten die Operationsklassen Auswertungsfunktionen die an jedem Knoten

im Ausdrucksbaum das Resultat aus den Ergebnissen der Operanden berechnen.

Im Wesentlichen existieren zwei Implementierungsansatze fur die Operationsklassen. Die erste Vari-

ante definiert fur unare und binare Operationen je eine allgemeine Operationsklasse mit einem zusatz-

lichen Template-Parameter (siehe Binary Expr in Listing 4.3), der die eigentliche Operation beschreibt.

Diese binare Operation wird durch eine Klasse mit einer statischen Funktion beschrieben, welche die

eigentliche Berechnung ausfuhrt (Plus in Listing 4.3). Mittels des Inlinings fur in-class definierte Metho-

den werden diese Funktionsaufrufe optimiert. Die Operationsklasse fur binare Operatoren stellt somit

nur eine Datenstruktur zum Speichern von Operanden und Ausfuhren einer binaren Operation dar.

Listing 4.3: ET-Programmiervariante mit allgemeinen Operationsklassen.

s t r u c t Plus

s t a t i c double app l y ( double l , double r )

r e t u r n l + r ;

;

template <c l a s s L , c l a s s R, c l a s s Op>

c l a s s B ina r y Exp r

p r i v a t e :

const L& l ;

const R& r ;

pub l i c :

B i na r y Exp r ( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const

Op : : app l y ( l . g i v e ( i ) , r . g i v e ( i ) ) ;

;

Diese Implementierungsvariante bietet den Vorteil, dass weniger Programmcode geschrieben werden

muss, da fur weitere binare Operationen bereits die Operationsklasse vorhanden ist, und nur noch die

Operation uber die Klasse mit einer statischen Methode definiert wird. Da durch diese allgemeinen

Operationsklassen bereits gewisse Schnittstellen definiert sind, benotigt eine solche Implementierung

keine zusatzliche Wrapper-Klasse mehr. In diesem Fall konnen die Operanden als Referenzen abgespei-

chert werden, da beim Aufbau einer Expression keine lokalen Objekte erstellt werden. Ein Nachteil

dieser Version ist sicherlich die etwas komplizierte und schwerer lesbare Programmierung, bei der die

eigentliche Operation erst aus den Template-Parametern ersichtlich ist. Daruber hinaus mussen fur eine

Implementierung ohne Wrapper neun oder mehr uberladene Versionen jedes Operators programmiert

werden.

Im zweiten Ansatz zur Implementierung der Operationsklassen wird fur jede Operation eine eigene

Klasse mit der entsprechenden Datenstruktur eingefuhrt, siehe Listing 4.4. Dadurch erhalt man einen

ubersichtlicheren aber etwas langeren Programmcode. Daruber hinaus kann hier nicht einfach auf die

Wrapper-Klasse verzichtet werden, da man die Operatoren sonst fur jede Kombination von Operations-

objekten uberladen musste. Der entscheidende Vorteil dieser Variante ist jedoch die bessere Lesbarkeit,

weshalb die weiteren Programmcodes nach dieser Variante prasentiert werden.

33

Page 50: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

4.2. KOMPONENTEN VON ET

Listing 4.4: ET-Programmcode mit separaten Operationsklassen.

template <c l a s s L , c l a s s R>

c l a s s Add i t i on

p r i v a t e :

const L& l ;

const R& r ;

pub l i c :

Add i t i on ( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const l . g i v e ( i ) + r . g i v e ( i ) ;

;

Betrachtet man die Laufzeit der beiden Implementierungen, so lassen sich keine wesentlichen Un-

terschiede feststellen, je nach verwendetem Compiler konnen beide Versionen etwas schneller oder

langsamer laufen. Jedoch konnen sich fur die unterschiedlichen Versionen durchaus verschiedene Uber-

setzungszeiten ergeben (Kapitel 8).

Um die Operationsklassen nicht mehr explizit mittels eines Wrappers kapseln zu mussen, kann man

wie bei den Grunddatenstrukturen die Klassen mittels der CRTP-Technik von der Wrapper-Klasse

ableiten. Dann besitzen die Operationsklassen durch die Konvertierung in den Basis-Typ ebenfalls den

gekapselten Typ.

Listing 4.5: Ableitung der Operationsklassen vom Wrapper mittels CRTP.

template <c l a s s L , c l a s s R>

c l a s s Add i t i on : pub l i c Expr<Add i t i on <A,B> > . . .

4.2.4 Creator Funktionen und Uberladene Operatoren

Das Uberladen der Operatoren mit den ET soll dazu dienen, effiziente und benutzerfreundliche Biblio-

theken zu schreiben, weshalb es fur eine einfache Handhabung notig ist, die komplizierten geschachtelten

Template-Klassen vor dem Benutzer zu verbergen. Dazu nutzt man die Moglichkeit in C++ templa-

tisierte Funktionen bzw. Operatoren zu definieren, die Aufrufe ohne explizite Angabe der Templates

erlauben, wenn diese bereits durch die Argumentlisten eindeutig bestimmt sind (type deduction, siehe

Abschnitt 2.3.1).

Listing 4.6: Vektor-Exponentialfunktion mit Creator-Funktion.

template <c l a s s A>

c l a s s Exponen t i a l : pub l i c Expr<A>

const A& a ;

pub l i c :

E x ponen t i a l ( const A& a ) : a ( a )

double g i v e ( i n t i ) const

r e t u r n s t d : : exp ( a . g i v e ( i ) ) ;

;

template <c l a s s A>

Exponent i a l <A>

i n l i n e Exp ( const Expr<A>& a )

r e t u r n Exponent i a l <A>(a ) ;

Mit solchen Creator Funktionen kann man einfache Schnittstellen zur Verfugung stellen und aus be-

stehenden ET-Konstrukten weitere erzeugen, ohne beim Aufruf deren genaue Template-Typen angeben

zu mussen. Durch die Deklaration als templatisierte Funktion generiert der Compiler die benotigten

Instanzen zur Ubersetzungszeit. Listing 4.6 beschreibt als Beispiel die komponentenweise Anwendung

der Exponentialfunktion auf Vektoren. Die Creator Funktion Exp dient dabei zur einfachen Erzeugung

eines entsprechenden ET-Objektes.

34

Page 51: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 4. ANALYSE VON ET UND VERBESSERUNGSANSATZE

Da der Funktionsrumpf solcher Creator Funktionen meist klein ist – es wird meist ja nur ein ent-

sprechender Konstruktor aufgerufen – werden diese als inline deklariert, um diesen zusatzlichen Funk-

tionsaufruf zu optimieren. Solche Funktionen zum Erstellen einer Expression finden in allen Teilen des

Programms Anwendung, wo keine passenden Operatoren uberladbar sind, z.B. Sinus-, Cosinus- oder

Exponentialfunktionen.

Ursprunglicher Initiator fur ET sind neben den Creator Funktionen die uberladenen Operatoren zum

Verknupfen von ET-Objekten. Ebenso wie die Creator Funktionen benotigen die uberladenen Versionen

der Operatoren keine explizite Spezifizierung der verwendeten Template-Typen. Diese generiert sich

der Compiler aus den Parameterlisten selbst. Aus diesem Grund konnen die Operationen in einem

Anwendungscode einfach sukzessive nacheinander geschrieben werden, der Compiler erzeugt daraus

die notigen Instantiierungen.

Weiter man durch die Einfuhrungen von Template-Spezialisierungen fur die uberladenen Operatoren

oder Creator Funktionen erreichen, dass fur bestimmte Templates besondere Objekte erzeugt werden

(siehe Abschnitt 7.4).

Die Implementierung der Operatoren ohne die Benutzung temporarer Objekte ist fur die Abspeiche-

rung der Operanden in den Operationsklassen als Referenzen essentiell. Denn nur wenn beim Erstellen

der Expression im uberladenen Operator keine lokalen Objekte erzeugt werden, bzw. ohne weitere

Abhangigkeiten, zeigen die gepeicherten Referenzen auf noch existierende Objekte.

4.3 Lebensdauer von ET-Objekten

In den bereits prasentierten Versionen der Implementierungen von ET werden die Operanden der Ope-

rationsklassen entweder als volle Memberobjekte oder als Referenzen auf bereits existierende Objekte

gespeichert. Je nach Programmierweise sind beide Methoden anzuwenden, aber nur unter genauer

Berucksichtigung der Lebensdauer der ET-Objekte.

Betrachten wir eine Implementierung, die durchweg volle Objekte als Membervariablen speichert.

Dies ist in den herkommlichen Versionen der ET mit expliziter Wrapper-Klasse notig, da beim Erzeugen

eines Ergebnistyps ein Operationsklassenobjekt (ExprT(a,b)) lokal erzeugt wird und in der Wrapper-

Klasse gespeichert werden soll.

template <c l a s s A, c l a s s B>

i n l i n e Expr<Bina ry Expr<Expr<A>,Expr<B>,Plus> >

ope ra to r+ ( const Expr<A>& a , const Expr<B>& b)

t ypede f Bina ry Expr<Expr<A>,Expr<B>,Plus> ExprT ;

r e t u r n Expr<ExprT>(ExprT ( a , b ) ) ;

Hierzu muss also das lokale Objekt ExprT(a,b) kopiert werden. Da dieses Objekt nach Beenden des

operator+ geloscht wird, wurde eine gespeicherte Referenz auf ein nicht mehr existentes Objekt zeigen.

Also ist es notig, dass sowohl in der Wrapper-Klasse, als auch in den Operationsklassen volle Objekte

verwendet werden. Speichert man jedoch auch auf der untersten Ebene die Vektoren als volle Objekte

ab, so werden beim Aufbau des Ausdrucks in Templates die auftretenden Vektoren jedesmal kopiert.

Offensichtlich fuhrt dies besonders bei großen Vektoren zu einem sehr ineffizientem Aufbau der ET.

Um dieses unnotige Kopieren der Vektoren zu umgehen, gibt es verschiedene Losungsansatze.

• Veldhuizen [Vel95] arbeitet in seiner Implementierung der ET mit der Abspeicherung der zu-

grunde liegenden Zeiger anstatt der Vektoren. Diese Zeiger werden beim Aufbau der Expressions

mittels der uberladenen Operatoren zwar kopiert, aber nicht das Array auf das sie zeigen. Diese

Programmierung umgeht zwar das ineffiziente Kopieren, aber sie ist beschrankt auf array-basierte

Datenstrukturen. Außerdem erhalt man keine durchgangige Kapselung der Daten, da die Zeiger

auf die Datenarrays gesondert vom Rest der Vektorobjekte benutzt werden.

35

Page 52: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

4.3. LEBENSDAUER VON ET-OBJEKTEN

• Der zweite Ansatz [VJ03] konzentriert sich darauf sicherzustellen, dass die Blatter der entstehen-

den Ausdrucksbaume nur als Referenzen gespeichert werden. Die Vektoren bestehen bereits vor

dem Aufbau der Expression und werden auch noch nach Beendigung der Berechnungen existieren.

Also konnen diese Objekte per Referenz gespeichert werden, wobei diese Referenz auch kopiert

werden kann, da das Objekt ja nicht geloscht wird. Die explizite Speicherung der Vektoren als

Referenzen innerhalb einer Expression kann mittels einer zusatzlichen Wrapper-Klasse fur die

Vektoren erreicht werden, durch geeignete Spezialisierungen der Operationsklassen oder spezielle

Versionen der uberladenen Operatoren. Dies erfordert aber eine weitere Indirektion beim Aufbau

der ET bzw. einen zusatzlichen Programmieraufwand beim Einfuhren der Spezialisierungen der

Operationsklassen.

• Verzichtet man auf eine explizite Wrapper-Klasse fur die Expressions, so konnen die uberladenen

Operatoren auf eine Weise implementiert werden, die ohne die Erzeugung von zusatzlichen loka-

len Objekten auskommen. Da dann keine gesonderten Kopien der ET-Objekte mehr durchgefuhrt

werden mussen, konnen durchgangig in den Operationsklassen Referenzen auf die Objekte ab-

gespeichert werden. Der Verzicht auf die Wrapper-Klasse benotigt aber – wie bereits erwahnt –

zusatzlichen Implementierungsaufwand, da hier mehrere Versionen von jedem uberladenen Ope-

ratoren definiert werden mussen. Diese Vielzahl an uberladenen Operatoren kann vermieden

werden, wenn die Operatoren durch allgemeine Template-Typen definiert werden, siehe Kapitel

5.2.

Wie im nachfolgenden Kapitel 5 dargestellt wird, ist es durchaus moglich Versionen von ET zu im-

plementieren, die nur mit Referenzen arbeiten, eine Wrapper-Klasse besitzen und mit nur je einer

uberladenen Operatorversion auskommen.

36

Page 53: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

Teil II

Weiterfuhrende Programmierung von

Expression Templates

Page 54: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen
Page 55: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 5. EINFACHE ET-IMPLEMENTIERUNG

5 Einfache ET-Implementierung

5.1 Komplexitat der Implementierung

Wie an dem Beispiel der gangigen ET-Programmierung aus Abschnitt 3.2.2 bereits ersichtlich wird,

erweist sich die Implementierung der Technik als durchaus anspruchsvoll. Denn es mussen fur jeden

Operatortyp mehrere sich ahnelnde uberladene Versionen eingefuhrt werden, was den resultierenden

Code umfangreich macht. So sind bei Implementierungen mit einer Wrapper-Klasse vier uberladene

Versionen je Operator zu definieren, bei Varianten ohne explizite Wrapper-Klasse mindestens neun.

Diese vielen Operatordefinitionen konnen prinzipiell durch die Implementierung der Operatoren mit

allgemeinen Templates vermieden werden, jedoch konnen dadurch leicht fehleranfallige Programme

entstehen. Zusatzlich mussen die Membervariablen in den Operationsklassen in korrekter Weise als

Referenzen bzw. ganze Objekte abgespeichert werden. Bei falsch deklarierten Membervariablen konnen

entweder ineffiziente Implementierungen oder auch nicht funktionierende Codes entstehen. Neben den

Schwierigkeiten der Programmierung, die leicht zu unubersichtlichen Fehlermeldungen fuhrt, berei-

tet auch die schlechte Testbarkeit der Implementierungen Probleme. Da templatisierte Klassen und

(Member-)Funktionen nur dann vom Compiler instantiiert werden, wenn sie im weiteren Verlauf des

Programms benotigt werden, konnen bestimmte Fehler einer ET-Implementierung erst durch entspre-

chende Beispiele aufgedeckt werden.

Aus diesen Grunden ist es von großem Interesse uber einfachere Techniken der ET-Implementierung

zu verfugen, die kurzer und weniger fehleranfallig sind als die herkommlichen Programmiervarianten.

Dafur werden in diesem Kapitel drei einfache Strategien prasentiert, die eine ubersichtliche und da-

mit intuitivere Programmierung der ET ermoglichen. Zuerst wird eine einfache Variante diskutiert, die

ohne die Verwendung einer Wrapper-Klasse funktioniert, dabei aber in bestimmten Fallen zu Mehrdeu-

tigkeiten beim Instantiieren des Compilers fuhrt. Als zweites wird die Vererbung zur Ubersetzungszeit

genutzt, um eine einfache und typsichere ET-Programmierung zu realisieren. Darauf aufbauend enthalt

Abschnitt 5.4 eine Implementierung zur Abspeicherung von ET-Objekten.

5.2 Namespace-gekapselte ET-Implementierungen

Die eigentliche Komplexitat bei der Programmierung von ET entsteht erst durch die Einfuhrung und

Verwendung von Wrapper-Klassen zur Definition entsprechender Schnittstellen. Dadurch mussen die

entstehenden Operationsklassen in den Operatoren gekapselt, sowie mehrfach uberladen werden. Da die

Schnittstellen der Operatoren auch mit allgemeinen Template-Parametern definiert werden konnen, ist

es durchaus moglich eine Variante der ET-Technik zu implementieren, die ohne jegliche Wrapper-Klasse

auskommt [AG05].

Listing 5.1 zeigt den Programmcode einer entsprechenden ET-Version ohne Wrapper-Klasse. Dazu

gehoren die Operationsklassen, in denen die Operanden als Referenzen abgespeichert werden konnen,

da beim Aufbau einer Expression keine lokalen Objekte benotigt werden. Als Argumente besitzen die

uberladenen Operatoren dann allgemeine Template-Parameter und erzeugen wiederum die entsprechen-

den Objekte der Operationsklassen. In der Vektorklasse ist der Zuweisungsoperator ebenfalls mit einem

allgemeinen Template-Typen uberladen, da ohne Wrapper-Klasse der Typ des Ausdrucksbaumes jede

Operationsklasse sein konnte. Um die Verwendung der uberladenen Operatoren etwas einzuschranken,

wird die gesamte Implementierung in einen Namensbereich myExpr einigebettet. Dadurch kann erreicht

39

Page 56: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

5.2. NAMESPACE-GEKAPSELTE ET-IMPLEMENTIERUNGEN

werden, dass die darin definierten uberladenen Versionen der Operatoren nur fur Objekte aus dem

Namensbereich verwendet werden.

Listing 5.1: Namespace-gekapselte ET-Implementierung.

namespace myExpr

template <c l a s s L , c l a s s R>

c l a s s Add i t i on

const L& l ; const R& r ;

5 pub l i c :

Add i t i on ( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const r e t u r n l . g i v e ( i ) + r . g i v e ( i ) ;

;

template <typename L , c l a s s R>

10 c l a s s S c a l a r M u l t i p l i c a t i o n

const L l ; const R& r ;

pub l i c :

S c a l a r M u l t i p l i c a t i o n ( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const

15 r e t u r n l ∗ r . g i v e ( i ) ;

;

template <c l a s s L , c l a s s R>

i n l i n e Add i t i on <L ,R> ope ra to r+(const L& l , const R& r )

20 r e t u r n Add i t i on <L ,R>( l , r ) ;

template <c l a s s R>

i n l i n e S c a l a r M u l t i p l i c a t i o n <double ,R> ope ra to r ∗( double l , const R& r )

r e t u r n S c a l a r Mu l t i p l i c a t i o n <double , R>( l , r ) ;

25

c l a s s Vector

. . .

template <c l a s s E>

vo id ope ra to r=(const E& e )

30 f o r ( i n t i =0; i<s i z e ; ++i )

data [ i ] = e . g i v e ( i ) ;

;

// end o f namespace

Doch diese Implementierung mit allgemeinen Templates fuhrt zu einigen unbeabsichtigten Neben-

effekten oder auch Fehlern in der Anwendung. Der Zuweisungsoperator in der Klasse Vector bietet

Benutzern die Moglichkeit, einem Vektor jedes Objekt zuweisen zu konnen, bis zu der Stelle, an wel-

cher die Funktion give aufgerufen wird. Damit erhalt man bei einer Zuweisung wie

Vector a ;

. . .

a = 5 . ;

eine nur schwer verstandliche Fehlermeldung, dass fur ein Element eines Nicht-Klassentyps versucht

wurde die give-Funktion aufzurufen. Stattdessen sollte der Compiler zum besseren Verstandnis melden,

dass keine passende Zuweisung dieser Art existiert. Dieses Problem konnte dadurch gelost werden,

indem der Zuweisungsoperator fur alle Operationsklassen uberladen wird. Dies widersspricht aber der

ursprunglichen Idee eine kurzere und einfachere Programmierung zu erzielen.

Daneben kann es zu einigen Problemen bei der Auswahl bzw. Instantiierung der templatisierten

Operatoren kommen. Diese konnen mit bestehenden Versionen in Konflikt geraten und zu Mehrdeu-

tigkeiten fuhren, siehe auch Abschnitt 2.2.1. Betrachten wir dazu als Beispiel die Programmierung

von komplexen Vektoren mit der skalaren Multiplikation, wie in Listing 5.1. Mochte man hiermit eine

einfache Multiplikation mit einem double-Wert durchfuhren,

40

Page 57: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 5. EINFACHE ET-IMPLEMENTIERUNG

Vector <s t d : : complex<double> > a , b ;

. . .

b = 5 . ∗ a ;

treten intern vorher nicht zu erwartende Mehrdeutigkeiten fur die interne Multiplikation eines double-

Wertes mit einem std :: complex<double>-Objekt auf (Zeile 15 in Listing 5.1).

An dieser Stelle stehen dem Compiler zwei Multiplikationsoperatoren zur Verfugung. Zum einen der

in der complex-Klasse definierte Operator

template <typename T>

complex<T> ope ra to r ∗( const T& a , const complex<T> b ) ;

welchen der Compiler eigentlich instantiieren musste. Zum anderen findet der Compiler im Namespace

myExpr auch noch den Operator

template <c l a s s R>

i n l i n e S c a l a r Mu l t i p l i c a t i o n <double , R>

ope ra to r ∗( double l , const R& r ) ;

der nach entsprechender Instantiierung ebenfalls zu den Parametern passen wurde. Zwar konnte auch

dieses Problem durch die Einfuhrung von samtlichen Spezialisierungen der Operatoren fur die Ope-

rationsklassen gelost werden, doch war die anfangliche Intention einen kurzeren Programmcode zu

erhalten.

5.3 Einfache, typsichere ET

Aufbauend auf der CRTP-Technik (Abschnitt 2.3.6) und der automatischen Typumwandlung (Ab-

schnitt 2.2.2) wird im Folgenden eine einfache und typsichere Programmierung der ET-Technik prasen-

tiert. Fur diese Implementierung, die anders als die vorher gezeigte Variante nicht zu Mehrdeutigkeiten

beim Instantiieren fuhren kann, benotigt man jedoch eine Wrapper-Klasse. Zu dieser lasst sich nach den

Ergebnissen aus Kapitel 4 feststellen, dass sie lediglich als einheitliche Schnittstelle der moglichen Aus-

drucke dient. Weiter wird diese Wrapper-Klasse immer nur in Zusammenhang mit einer abgeleiteten

Klasse verwendet.

Deshalb bietet es sich an, die Wrapper-Klasse mittels der bereits in Kapitel 4 entwickelten Ideen

zu realisieren und die Operationsklassen, sowie die Vektordatenstruktur von dieser Wrapper-Klasse

abzuleiten.

Der Programmcode 5.2 prasentiert die resultierende einfache ET-Implementierung. Darin enthalt der

Wrapper Expr einen Cast-Operator, mittels dem der Compiler ein durch den Wrapper gekapseltes Objekt

in das ursprungliche Objekt zuruck konvertieren kann. Zusatzlich ist eine Auswertungsfunktion give

definiert, welche die Berechnungen der i-ten Komponente an das gekapselte Objekt weitergibt. Weiter

folgt die Implementierung der Operationsklasse fur die Addition zweier Ausdrucke. Dabei werden der

linke und rechte Teil des Ausdrucksbaumes als konstante Referenzen gespeichert. Die Auswertung der

i-ten Komponente berechnet die Summe der jeweiligen Ergebnisse der Teilbaume. Zusatzlich wird die

Operationsklasse fur die Multiplikation von beliebigen skalaren Werten mit Ausdrucken gezeigt. In

den Zeilen 29 bis 40 enthalt Listing 5.2 die uberladenen Operatoren + und ∗. Dazu ist zu bemerken,

dass die Template-Parameter der Operationsklassen ohne die kapselnden Wrapper-Typen angegeben

werden. Dadurch wird beim Ubergeben der Operanden an die Konstruktoren der Cast-Operator der

Wrapper-Klasse aufgerufen.

Die Vector-Klasse selbst wird ebenfalls mittels CRTP als Ableitung der Wrapper-Klasse definiert.

Damit ist nur eine Version je Operator zu implementieren, denn ein Vector-Objekt hat dadurch den Typ

Expr und passt somit zu den bereits uberladenen Operatoren. Die Schnittstelle im Zuweisungsoperator

41

Page 58: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

5.3. EINFACHE, TYPSICHERE ET

bildet ebenfalls ein Objekt vom Typ Expr, und da die Wrapper-Klasse ebenfalls eine give-Funktion

besitzt, kann das ubergebene Objekt einfach ausgewertet werden.

Listing 5.2: Programm-Code einer einfachen ET-Variante.

template <c l a s s E>

s t r u c t Expr

ope ra to r const E& () const

r e t u r n ∗ s t a t i c c a s t <const E∗>( t h i s ) ;

5

double g i v e ( i n t i ) const

r e t u r n s t a t i c c a s t <const E&>(∗ t h i s ) . g i v e ( i ) ;

;

10

template <c l a s s L , c l a s s R>

c l a s s Add i t i on : pub l i c Expr<Add i t i on<L ,R> >

const L& l ;

const R& r ;

15 pub l i c :

Add i t i on ( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const r e t u r n l . g i v e ( i ) + r . g i v e ( i ) ;

;

20 template <typename L , c l a s s R>

c l a s s S c a l a r M u l t i p l i c a t i o n

: pub l i c Expr<S c a l a r M u l t i p l i c a t i o n <L ,R> >

const L l ;

const R& r ;

25 pub l i c :

S c a l a r M u l t i p l i c a t i o n ( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const r e t u r n l ∗ r . g i v e ( i ) ;

;

30 template <c l a s s L , c l a s s R>

i n l i n e Add i t i on <L ,R>

ope ra to r+(const Expr<L>& l , const Expr<R>& r )

r e t u r n Add i t i on <L ,R>( l , r ) ;

35

template <c l a s s R>

i n l i n e S c a l a r Mu l t i p l i c a t i o n <double , R>

ope ra to r ∗( double l , const Expr<R>& r )

r e t u r n S c a l a r Mu l t i p l i c a t i o n <double , R>( l , r ) ;

40

c l a s s Vector : pub l i c Expr<Vector >

. . .

template <c l a s s E>

45 vo id ope ra to r=(const Expr<E>& e )

f o r ( i n t i =0; i<s i z e ; ++i )

data [ i ] = e . g i v e ( i ) ;

;

Insgesamt bildet Listing 5.2 damit eine komplette Implementierung fur die komponentenweise Addi-

tion und Multiplikation von Vektoren. Es fehlen lediglich die Konstruktoren sowie der Destruktor der

Vektor Klasse. Wie bei der vorherigen Implementierung ohne Wrapper-Klasse konnen hier alle Ope-

randen als Referenzen gespeichert werden, da auch hier in den uberladenen Operatoren keine lokalen

Objekte erzeugt werden.

Als Variante dieser Implementierung kann auf die Auswertungsfunktion in der Wrapper-Klasse ver-

42

Page 59: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 5. EINFACHE ET-IMPLEMENTIERUNG

zichtet werden. Dafur muss aber im Zuweisungsoperator der Vektorklasse das ubergebene gekapselte

Objekt vom Typ Expr<E> erst explizit in E umgewandelt werden.

template <c l a s s E>

s t r u c t Expr

i n l i n e ope ra to r const E& () const

r e t u r n ∗ s t a t i c c a s t <const E∗>( t h i s ) ;

;

. . .

c l a s s Vector : pub l i c Expr<Vector >

. . .

template <c l a s s E>

vo id ope ra to r=(const Expr<E>& e )

const E& expr ( e ) ;

f o r ( i n t i =0; i<s i z e ; ++i )

data [ i ] = expr . g i v e ( i ) ;

;

5.4 Einfache ET fur temporare Ausdrucke

Eine ET-Programmierung die – wie vorher gezeigt – nur mit Referenzen in den Operationsklassen

arbeitet, kann jedoch nicht immer benutzt werden. Beispielsweise muss fur die Speicherung von ET-

Objekten eine Implementierung verwendet werden, die durchgangig voll abgespeicherte Operanden

in den Operationsklassen besitzt, wie in Abschnitt 7.3 beschrieben. Da in diesem Fall die gesamten

Ausdrucke mit den Terminalen gesichert werden sollen, kann einfach die vorherige Implementierung

ohne die Referenzen der Membervariablen verwendet werden.

Beispielsweise entstehen beim Aufbau eines Ausdrucksbaumes fur geschachtelte ET-Programme (Ka-

pitel 7.1) temporare Operanden, die wiederholt kopiert und als volle Objekte abgespeichert werden

mussen. Hierbei ist es nicht sinnvoll eine Implementierung mit durchweg vollen Objekten zu verwen-

den, denn somit wurden auch die Vektoren in jedem Operanden voll kopiert und abgespeichert. Dies

hatte vor allem bei großen Vektoren einen nachteiligen Einfluss auf die Performance. In den herkomm-

lichen ET-Implementierungen wurde dies generell durch eine Spezialisierung der Operationsklassen

bzw. durch entsprechend uberladene Operatoren realisiert [Han96, Vel01, Fur97]. Dies hatte naturlich

wiederum langwierige und wegen den zusatzlichen Spezialisierungen auch schwerer wartbare Imple-

mentierungen zur Folge.

Listing 5.3: ET-Implementierung zur Speicherung temporarer Operanden.

template<c l a s s E>

s t r u c t Expr

ope ra to r const E& () const r e t u r n ∗ s t a t i c c a s t <const E∗>( t h i s ) ;

4 ;

template<c l a s s E>

s t r u c t Expr<const E&>

ope ra to r const E& () const r e t u r n ∗ s t a t i c c a s t <const E∗>( t h i s ) ;

;

9 template <c l a s s L , c l a s s R>

c l a s s Add i t i on : pub l i c Expr<Add i t i on<L ,R> >

L l ; R r ;

pub l i c :

Add i t i on (L l , R r ) : l ( l ) , r ( r )

14 double g i v e ( i n t i ) const . . .

;

c l a s s Vector : pub l i c Expr<const Vector&> . . . ;

43

Page 60: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

5.4. EINFACHE ET FUR TEMPORARE AUSDRUCKE

Aus diesem Grund wurde fur die vorliegende Arbeit eine zusatzliche Implementierungsvariante der

ET-Version aus Listing 5.2 entwickelt, die mit voll abgespeicherten Operanden arbeitet, außer, wenn

es sich bei den Operanden um Vector-Objekte handelt. Der resultierende Programmcode benotigt nur

eine zusatzliche Spezialisierung der Wrapper-Klasse.

Dazu wird die Klasse Vector von der Wrapper-Klasse nicht mit sich selbst als Typ abgeleitet, son-

dern mittels Expr<const Vector&>. Da der benutzerdefinierte Konvertierungsoperator der bestehenden

Wrapper-Implementierung mit diesem Template-Typ nicht instantiiert werden kann, muss zusatzlich

eine spezialisierte Version der Klasse Expr implementiert werden. Diese Spezialisierung behandelt den

Fall, dass der Template-Typ eine konstante Referenz ist (Zeilen 5 bis 8 in Listing 5.3). In der Operati-

onsklasse werden die Operanden nun als ganze Objekte verwendet, ebenso in der Parameterubergabe

des Konstruktors.

Wird diese Implementierung benutzt um die Summe von zwei Vektoren zu berechnen, etwa a = b + c,

so wird uber den uberladenen Plusoperator – unter Verwendung der Konvertierung aus Zeile 7 in Listing

5.3 – ein Objekt vom Typ

Add i t i on <const Vector &, const Vector&>

generiert, in dem nur Referenzen der Vektoren abgespeichert sind. Addiert man aber drei Vektoren,

so ergibt sich auf Grund der anderen Vererbung der Additionsklasse ein Objekt mit dem folgenden

Datentyp:

Add i t i on <Add i t i on <const Vector &, const Vector &>,const Vector &>.

Durch die spezialisierte Vererbung der Vektorklasse kann also die Art der Operandenabspeicherung

gesteuert werden.

Alle hier prasentierten einfachen Implementierungen liefern naturlich ebenso performante Program-

me wie die traditionellen Versionen von ET, da die Optimierungen mittels Inlining aquivalent durch-

gefuhrt werden konnen. Doch wie bereits angekundigt, bestehen bei den herkommlichen Implementie-

rungsvarianten – sowie auch bei der einfachen Version – weitere Optimierungslucken, die im folgenden

Kapitel genauer untersucht werden.

44

Page 61: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 6. FAST EXPRESSION TEMPLATES

6 Fast Expression Templates

6.1 ET im Hochleistungsrechnen

Da die Verwendung von C++ zur Programmierung von Losungen numerischer Problemstellungen

sehr verbreitet ist, werden die performanten ET-Bibliotheken insbesondere auch fur den Einsatz auf

Hochleistungsrechnern benotigt. Gerade auf diesen Rechnern ist es wichtig, dass die jeweiligen Compiler

die alle relevanten Optimierungen durchfuhren konnen, um die plattformspezifischen Rechenleistungen

entsprechend ausnutzen zu konnen.

6.1.1 Aliasing-Probleme bei ET

Wie bereits in Kapitel 4.1 angedeutet, konnen die geschachtelten Aufrufe zur Auswertung der ET-

Objekte durch Inlining optimiert werden, was im Prinzip einer direkten Auswertung der Arrays der

zugrunde liegenden Vektordatenstrukturen im C-Stil entspricht.

Doch eine gute Optimierung von vektorbasierten ET-Codes benotigt nicht nur ein vollstandiges

Inlining. Zusatzlich muss der Compiler die Aliase der Zeigervariablen auflosen, um ein performantes

Programm zu erhalten, siehe Kapitel 2.4.3. Auf Grund der geschachtelten Template-Strukturen und den

in Vektorklassen gekapselten Zeigern schaffen es Compiler aber nicht, diese Optimierung wie gewunscht

durchzufuhren, da sie nicht vollstandig sicherstellen konnen, wieviele Aliase fur den entsprechenden

Speicherbereich existieren. Zur genaueren Analyse wird das folgende Beispiel herangezogen, das wie die

Vektortriade auf Berechnungen mit der komponentenweisen Addition und Multiplikation von Vektoren

zuruckgreift.

Vector a , b , c ;

. . .

c = a + b ∗ a ;

Hierbei sollte nach Optimierung der give-Funktionen im Zuweisungsoperator (siehe dazu auch Ab-

schnitt 4.1) die Performance des folgenden Ausdrucks erreicht werden.

c . da ta [ i ] = a . da ta [ i ] + b . da ta [ i ]∗ a . da ta [ i ] ;

Doch innerhalb dieses Ausdrucks existieren mit den beiden Vektoren a im Ausdrucksbaum zwei Da-

tenzeiger, die auf den gleichen Speicherbereich zeigen. Bei solchen Aliasen in einem Ausdruck konnte

ein Zeiger zwischenzeitlich die Daten des zugrunde liegenden Arrays verandern und somit fur eine Ver-

wendung beim nachsten Zeiger ein neues Laden der Arraydaten in den Cache erforderlich machen. Um

bei Optimierungen keinen fehlerhaften Code zu erzeugen, haben C++-Compiler ein sehr konservatives

Konzept zum Auflosen solcher Mehrfachreferenzierungen. Konnen im Falle von wiederholt auftretenden

Variablen in einem Ausdruck diese Zeiger nicht miteinander identifiziert werden, beeintrachtigt dies

offensichtlich die Performance.

Diese Aliasing-Probleme von ET-Implementierungen wurden zuerst von Basetti, Davis und Quinlan

in [BDQ97] veroffentlicht. Darin zeigen sie die register spillage von ET-Codes, indem sie die Perfor-

mance von Ausdrucken bei einer steigenden Anzahl von Operationen betrachten. Daraus wird deut-

lich, dass die erreichbare Leistung der Ausdrucke mit wiederholt auftretenden Vektoren deutlich unter

der des C-Codes liegt. Diese register spillage lasst sich auf das vorher beschriebene Aliasing-Problem

45

Page 62: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

6.2. FAST EXPRESSION TEMPLATES

zuruckfuhren. Zur Vermeidung dieser Probleme fuhrte die Bibliothek tvmet (tiny vector matrix expres-

sion templates) [Pet03] Implementierungen ein, die speziell fur kleine Vektoren ohne interne Zeiger

bzw. dynamische Arrays arbeiten. Stattdessen wurden die Vektorklassen um einen Template-Integer

erweitert, der die Dimension des Vektors enthalt, die dann naturlich nicht dynamisch ist. Intern wurden

damit die Daten nicht mit Zeigern und Arrays reprasentiert, sondern es wurden fur jede Dimension

eine Spezialisierung der Vektorklasse definiert, die eine entsprechende Zahl an Membervariablen be-

sitzt. Zur Verwendung dieser Vektoren muss also bereits mittels Templates die Dimension angegeben

werden, was naturlich die Flexibilitat der Anwendung einschrankt.

Neben dem nicht vollstandig aufgelosten Aliasing bestehen gerade fur kleine Vektoren noch große

Unterschiede in der Leistungsfahigkeit zwischen ET- und C-Codes. Dies liegt daran, dass der Aufbau

der ET-Objekte vor allem fur kleine Vektoren durch das Erstellen der Operationsklassen-Objekte die

Performance deutlich beeinflusst. Dies zeigen unter anderem die Laufzeitanalysen in Abschnitt 6.3. Im

Folgenden werden Implementierungsvarianten fur ET prasentiert, die den Compiler beim Auflosen des

Aliasings der Datenzeiger unterstutzen, sowie die Performance von kleinen Vektoren verbessern, ohne

dabei die Flexibilitat einzuschranken.

6.2 Fast Expression Templates

Die Programmierung von Fast Expression Templates (FET) wurde zunachst in einer sehr eingeschrank-

ten Form speziell fur die Hitachi SR8000 (Pseudo-Vektor-Maschine) entwickelt [LP03]. Diese Varian-

te kopierte die Datenpointer vor der Auswertung in globale Zeiger, was im Prinzip einem externen

Auflosen des Aliasings entspricht. Ein großer Nachteil war dabei jedoch, dass diese Implementierung

nur fur eine feststehende Maximalanzahl von Vektoren funktionierte, bzw. die Verwendung von mehr

Vektoren zusatzliche Erweiterungen im Code erforderte.

Die generelle Entwicklung der FET-Technik wurde in [HLP06b] und [HLP05] veroffentlicht. Dabei

wurden die Template-Nummerierung und die Meta-FET nur in Kombination betrachtet. Nachfolgend

werden die Methoden getrennt vorgestellt, denn bereits die Anwendung der Template-Nummerierung

allein lost die angesprochenen Aliasing-Probleme.

6.2.1 Template-Nummerierung der Vektorklassen

Im Rahmen der vorliegenden Arbeit wird ausgehend vom Listing 2.1 die dort aufgefuhrte Vektorklasse

um einen Integer als Template-Parameter erweitert. Dieser soll dazu dienen, Vektoren mit verschiedenen

Typen zu erzeugen und damit die Funktionalitat von Objekten einer Klasse (Vector) auf Objekte von

verschiedenen Klassentypen (Fast Vector<int> mit unterschiedlichen Integern) zu ubertragen. Zusatzlich

werden die Datenzeiger innerhalb der templatisierten Vektorklassen als statisch deklariert, woraus

folgt, dass alle Vektoren mit dem gleichen Template-Index den gleichen Datenzeiger besitzen. Der

Speicherplatz fur diesen Zeiger selbst muss – wie bei statischen Variablen ublich – außerhalb der

Klasse angefordert werden. Neben diesen Anderungen kann die Implementierung der Vektorklasse

ubernommen werden, was insbesondere heißt, dass das Array, auf welches der Pointer zeigt, weiterhin

dynamisch ist, und somit keinerlei Information uber Vektorgroßen zur Ubersetzungszeit benotigt wird.

Der ubrige Teil der ET-Implementierung, die Operationsklassen und die uberladenen Operatoren, bleibt

unverandert. Listing 6.1 zeigt dem entsprechend die Implementierung der Klasse Fast Vector.

Bei Verwendung dieser nummerierten Klasse besitzen alle Vektorobjekte mit identischem Index den

gleichen statischen Pointer und zeigen damit auf das gleiche Array. Deshalb muss bei der Verwendung

dieser Variante der Anwender jeden Vektor mit einem anderen Index initialisieren. Um Benutzungs-

fehler zu vermeiden, kann man mit einem einfachen Test innerhalb der Vektorklasse sicherstellen,

dass jeder nummerierte Vektor nur einmal auftritt. Dazu uberpruft man beispielsweise zu Beginn der

Konstruktoren, ob der Daten-Pointer noch auf NULL zeigt. Falls nicht, so ist der Fast Vector mit dem

46

Page 63: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 6. FAST EXPRESSION TEMPLATES

entsprechenden Template-Integer bereits in Benutzung.

Listing 6.1: Template-nummerierte Vektordatenstruktur.

template < i n t un ique I d >

c l a s s Fa s t Vec to r : Expr<Fas t Vecto r <un ique I d > >

p r i v a t e :

s t a t i c double ∗ data ;

i n t s i z e ;

pub l i c :

. . .

;

template < i n t un ique I d >

double ∗ Fas t Vecto r <un ique I d > : : da ta = NULL ;

Mittels dieser Template-Nummerierung und der Einfuhrung von statischen Pointern kann der Com-

piler beim Ubersetzen schon anhand der auftretenden Datentypen entscheiden, wie die statischen Zeiger

verwendet werden. Das Aliasing mehrfach auftretender gleicher Vektoren kann aufgelost werden, da

erkennbar ist, dass die statischen Pointer auf das selbe Datenarray zeigen und welche Zeiger dieses

Array wirklich verandern. Dadurch werden bei der Ausfuhrung des Programms bereits in den Cache

geladene Daten nicht wieder neu angefordert, was die vorher aufgefuhrten Probleme behebt.

Die Anwendung dieser Implementierung unterscheidet sich lediglich bei der Initialisierung der Vek-

toren von den vorher prasentierten Versionen. Der Anwender muss dabei die Fast Vector-Objekte mit

einem Template-Integer anlegen. Zusatzlich ist sicherzustellen, dass diese Integer eindeutig sind, was

– wie bereits erwahnt – durch eine entsprechende Implementierung unterstutzt werden kann. Daruber

hinaus sind keine weiteren Besonderheiten zu berucksichtigen, die Vektoren konnen in gewohnter Weise

verwendet werden.

Fa s t Vec to r <1> a ( s i z e ) ;

Fa s t Vec to r <2> b ( s i z e ) ;

Fa s t Vec to r <3> c ( s i z e ) ;

. . .

c = a + b ∗ a ;

Ein genauer Vergleich der Performance dieser Implementierung mit einer ohne ET wird in den

Abschnitten 6.3.2 und 6.3.3 behandelt. Zunachst soll aber eine ET-Implementierung prasentiert werden,

die ausschließlich mit Typinformationen arbeitet.

6.2.2 Meta-FET

Aufbauend auf der Template-Nummerierung der Vektoren kann eine Implementierung definiert werden,

welche lediglich die Typen der erzeugten Objekte benotigt. Die eindeutige Nummerierung der Vekto-

ren und den damit eingefuhrten statischen Zeigern, ordnet jedem Datenpointer einen eigenen Typ zu.

Dadurch kann durch die Benutzung von statischen Zugriffs- und Auswertungsfunktionen eine Auswer-

tung der ET rein uber die geschachtelten Template-Typen implementiert werden. Dadurch mussen die

Operanden nicht mehr als Member-Variablen in den Operationsklassen abgespeichert werden, so dass

auch keine spezifischen Konstruktoren mehr benotigt werden. Die Wrapper-Klasse besitzt auch keinen

Cast-Operator mehr, da auf Grund der rein typ-basierten ET keine Konvertierungen notig sind, siehe

dazu die Implementierung in Listing 6.2.

In den uberladenen Operatoren werden also nur leere Objekte erzeugt, da im Weiteren nur die Typen

fur die Auswertung verwendet werden. Diese Auswertung geschieht dann durch die statischen Aufrufe

der Operations- bzw. Vektorklassen.

47

Page 64: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

6.2. FAST EXPRESSION TEMPLATES

Listing 6.2: Meta-FET-Implementierung ohne Abspeicherung der Operanden.

template <c l a s s A> s t r u c t Expr ;

template <c l a s s L , c l a s s R>

s t r u c t Add i t i on : pub l i c Expr<Add i t i on <L ,R> >

5 s t a t i c double g i v e ( i n t i )

r e t u r n L : : g i v e ( i )+R : : g i v e ( i ) ;

;

10 template <c l a s s L , c l a s s R>

i n l i n e Add i t i on <L ,R>

ope ra to r +(const Expr<L>& a , const Expr<R>& b)

r e t u r n Add i t i on <L ,R>() ;

15

template < i n t un ique I d >

c l a s s Fa s t Vec to r : Expr<Fas t Vecto r <un ique I d > >

. . .

s t a t i c double g i v e ( i n t i )

20 r e t u r n data [ i ] ;

template <c l a s s E>

vo id ope ra to r=(const Expr<E>& e )

f o r ( i n t i =0; i<s i z e ; ++i )

25 data [ i ] = E : : g i v e ( i ) ;

;

template < i n t un ique I d >

double ∗ Fas t Vecto r <un ique I d > : : da ta = NULL ;

Bei Erweiterungen der FET aus Listing 6.2 fur die Multiplikation von Vektoren mit Skalaren gibt

es jedoch zusatzliche Besonderheiten. Da diese Technik nur auf Typinformationen beruht, mussen aus-

drucksspezifische Daten in einem eigenen Typen gekapselt werden. Dazu sind genau wie bei Fast Vector

nummerierbare Klassen fur Skalare einzufuhren.

Listing 6.3: Nummerierbare Klasse zur FET-Kapselung von Skalaren.

template < i n t un ique I d >

c l a s s Double : pub l i c Expr<Double<un ique I d > >

double v a l u e ;

pub l i c :

Double ( double d ) : v a l u e ( d )

s t a t i c double g i v e ( i n t i )

r e t u r n v a l u e ;

;

template < i n t un ique I d >

double Double<un ique I d > : : v a l u e ;

Damit kann dann nach entsprechender Einfuhrung von Double-Variablen aus Listing 6.3 eine skalare

Multiplikation folgendermaßen durchgefuhrt werden.

Fas t Vecto r <1> a ; Fas t Vecto r <2> b ;

Double<1> c ( 5 . ) ;

. . .

a = c ∗ b ;

Wie wir spater noch sehen werden, ist diese zusatzliche Kapselung der skalaren Werte lediglich in sehr

eingeschrankten Teilen der FET-Anwendungen notig (Abschnitt 6.4).

48

Page 65: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 6. FAST EXPRESSION TEMPLATES

6.3 Leistungsanalyse der FET-Implementierungen

Nach der Einfuhrung der template-nummerierten Vektoren und der Meta-FET-Implementierung wird

nun die Performance dieser Varianten analysiert. Nach einigen allgemeinen Anmerkungen zu den

prasentierten Untersuchungen wird zunachst die Verwendung von FET auf Workstations erortert.

Danach werden die erzielten Performance-Resultate der Implementierung in Kombination mit auto-

matischen Vektorisierung auf Vektorrechnern bzw. der Parallelisierung mittels OpenMP auf Clustern

zusammengefasst und diskutiert.

6.3.1 Allgemeine Bemerkungen zur Analyse

Als erstes Testbeispiel zum Vergleich der verschiedenen Implementierungen wird die Performance der

Vektortriade betrachtet,

a = b + c ∗ d, (6.1)

die offensichtlich keine Aliase aufweist. Damit soll zunachst uberpruft werden, ob die neuen Implemen-

tierungen so effizient sind, wie die klassischen Varianten. Als zweites wird mit

b =

7∑

i=1

ai (6.2)

ein Beispiel mit massivem Aliasing diskutiert. Neben diesen etwas trivialen Beispielen werden zusatz-

lich die zwei- bzw. dreidimensionalen Poisson-Probleme auf einem strukturierten Gitter betrachtet.

Der Fokus liegt grundsatzlich in der Anwendbarkeit der FET-Implementierungen, und nicht auf beson-

ders komplex angelegten Problemstellungen. Diskretisiert werden die Probleme durch die Standard-

Sterne der Finiten Differenzen (Funf-Punkte-Stern in 2D) sowie der Finiten Elemente Diskretisierungen

(Neun-Punkte- bzw. 27-Punkte-Stern). Um eine durchgangige Auflosung des Aliasings untersuchen zu

konnen, wird ein Jacobi-Verfahren zur Losung der numerischen linearen Gleichungen benutzt [SB02].

Da beim Jacobi-Loser die Zuweisung des Ergebnisses nach jedem Iterationsschritt erfolgt – anders als

beim Gauß-Seidel-Verfahren – mussen keine Daten wahrend eines Berechnungsschrittes neu geladen

werden.

Betrachtet man die Performance der ET- und FET-Implementierungen mittels der durchgefuhrten

Rechenoperationen pro Zeiteinheit (FLOPs), so entsteht bei dem Ausdruck (6.2) das Problem, dass

die Effizienz der FET-Implementierung uber der Peak-Performance der jeweiligen Rechner liegen kann.

Nach eingehender Betrachtung wird jedoch ersichtlich, dass der erzeugte Programmcode anstatt der

27 Additionen bzw. Multiplikationen durch Anwenden des Horner-Schemas

b = a(1 + a(1 + a(1 + a(1 + a(1 + a(1 + a))))))

nur noch 12 Gleitpunktoperationen benotigt. Bei klassischen ET konnen diese Optimierung zur Re-

duzierung der Operationen jedoch nicht durchgefuhrt werden, so dass ein Vergleich der FLOPs nicht

sinnvoll ist. Aus diesem Grund wird die Zeit betrachtet, die der Rechner benotigt, um den Ergeb-

nisvektor zu berechnen. Dazu werden die entsprechenden Ausdrucke mehrmals ausgewertet, um eine

sinnvolle Zeitmessung zu erhalten. Daraus berechnen sich dann die Werte Zeit pro Iterationsschritt.

Da die betrachteten Zeitunterschiede der verschiedenen Implementierungen exponentiell mit der

Große der eingesetzten Vektoren zunehmen, werden die prasentierten Graphen fur beide Achsen in

logarithmischer Skalierung dargestellt.

6.3.2 Effizienz auf Workstations

Zunachst werden die neuen Implementierungsvarianten auf herkommlichen Workstations, einem Intel

Pentium 4 bzw. einem Intel Dual Core Rechner untersucht. Eine ausfuhrliche Beschreibung der platt-

formspezifischen Daten ist in Anhang D.1.1 bzw. D.1.2 aufgefuhrt. Als Compiler werden verschiedene

49

Page 66: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

6.3. LEISTUNGSANALYSE DER FET-IMPLEMENTIERUNGEN

Versionen des GNU-C++-Compilers (Versionen 3.3.2 bis 4.1.0) sowie den Intel-C++-Compiler (Ver-

sion 8.1) verwendet. Da die erhaltenen Ergebnisse alle sehr ahnlich sind, werden hier die aktuellsten

Ergebnisse auf einem Intel Dual Core prasentiert, ubersetzt mit dem GNU-Compiler, Version 4.1.0.

Abbildung 6.1 enthalt zwei Graphen mit je vier Performance-Kurven, einer Implementierung in C

ohne ET (NET), einer Version mit klassischen ET (CET), die Variante mit nummerierten Vektoren

(EET) sowie eine Programmierung mittels Fast Expression Templates (FET).

'RÚEDER6EKTOREN

:E

ITP

RO)

TERA

TIO

N

.%4 # #ODEOHNE%4#%4 +LASSISCHE%4%%4 .UMMERIERTE%4&%4 3CHNELLE%4

:E

ITP

RO)T

ERA

TIO

N

'RÚEDER6EKTOREN

.%4 # #ODEOHNE%4#%4 +LASSISCHE%4%%4 .UMMERIERTE%4&%4 3CHNELLE%4

Abbildung 6.1: Vergleich der Performance von Implementierungen ohne ET (NET), klassischen ET

(CET), nummerierten Vektoren (EET) und FET auf einem Pentium 4, ubersetzt mit dem GNU-C++-

Compiler, Version 4.1.0. Links: Problem (6.2) mit massivem Aliasing. Rechts: 2D-Poisson (Funf-Punkte-

Stern) gelost mittels dem Jacobi-Verfahren.

Die linke Abbildung zeigt die Leistung der Implementierung des Ausdrucks (6.2), der unter massivem

Aliasing steht. Dabei erreicht die Meta-FET-Implementierung die Leistung der Programmierung in C,

die beidemale viermal, stellenweise sogar sechsmal schneller sind als die Variante mittels klassischen

ET. Die Implementierung mit nummerierten Vektoren ist ab einer Vektorgroße von 100 ebenso effizient

wie die Meta-FET-Version, lediglich fur kleinere Vektorgroßen zeigt sich der Overhead, der durch den

Aufbau der Ausdrucke entsteht.

Die rechte Grafik zeigt das Laufzeit-Verhalten der vier Implementierungen bei einem 2D-Poisson-

Problem, diskretisiert mittels einem Finite-Differenzen-Funf-Punkte-Stern. Da in diesem Beispiel das

Aliasing-Problem weniger ausgepragt ist, konnen hierbei auch nicht so große Unterschiede festgestellt

werden. Wie vorher lauft die Meta-FET-Variante so gut wie der C-Code. Die nummerierten Vektoren

ergeben fur Probleme, die in den Cache passen, 50% dieser Laufzeiten. Betrachtet man jedoch die

klassische ET-Variante, so hat die Verwendung von nummerierten Vektoren bereits eine Verdopplung

der Laufzeiten zur Folge, die Anwendung von Meta-FET sogar eine Vervierfachung.

6.3.3 FET auf Hochleistungsrechnern

Die angesprochenen Aliasing-Probleme sind zwar – wie in den Grafiken 6.1 gezeigt – auch auf gewohn-

lichen Workstations mit den gangigen Compilern zu bemerken. Doch die Auswirkungen auf die Perfor-

mance sind auf Hochleistungsrechnern, wie z.B. auf Plattformen, die mit automatischer Vektorisierung

oder Parallelisierung arbeiten, deutlicher ausgepragt. Denn fur die parallelen Aufteilungen und Berech-

nungen ist ein vollstandiges Auflosen der Abhangigkeiten unverzichtbar, um effiziente Programme zu

erhalten.

Die folgenden Performance-Ergebnisse beschranken sich auf Meta-FET-Programme, herkommliche

ET-Varianten und die entsprechenden Codes ohne die Verwendung von ET. Da die nummerierten

Vektoren mit einer klassischen ET-Programmierung ab einer Vektorgroße von 100 ebenso schnell wie die

50

Page 67: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 6. FAST EXPRESSION TEMPLATES

Meta-FET laufen, wird hier aus Grunden der Ubersichtlichkeit auf die Prasentation dieser Ergebnisse

verzichtet.

Performance auf Vektorcomputern

Fur eine effektive Vektorisierung ist ein vollstandiges Auflosen der Pointerabhangigkeiten unumgang-

lich [HLR05]. Um die Verbesserungen der FET-Variante bzgl. einer automatischen Vektorisierung zu

testen, werden die Implementierungen auf der Hitachi SR8000 am LRZ Munchen sowie der NEC

SX-6/48M am HLRS Stuttgart betrachtet. Eine genaue Beschreibung der Plattformen findet sich in

Anhang D.2.1 bzw. D.2.2. Die nachfolgenden Performance-Ergebnisse beschranken sich auf Untersu-

chungen der NEC SX-6/48M, da die resultierenden Leistungskurven auf der Hitachi sehr ahnlich sind

und keine wesentlichen Unterschiede aufzeigen.

,ËNGEDER6EKTOREN

NOIT

ARET)

ORPTI

E:

.%4 # #ODEOHNE%4# % 4 + L A S S I S C H E % 4&%4 &AST %4

,ËNGEDER6EKTOREN

NOIT

ARET)

ORPTI

E:

.%4 # #ODEOHNE%4# % 4 + L A S S I S C H E % 4&%4 &AST %4

Abbildung 6.2: Performance-Ergebnisse auf der NEC SX-6. Links: Betrachtung der Vektortriade (6.1),

bei der die Vorteile der FET-Implementierung fur kleine Vektoren erkennbar sind. Rechts: (6.2), ein

Term mit massivem Aliasing, woraus die Unterschiede der klassischen ET zu der FET-Variante deutlich

erkennbar sind.

Zur Analyse der Effizienz der Implementierungen wird zunachst die Vektortriade betrachtet, die

keinerlei Aliasing-Probleme aufwirft. Dennoch kann fur kleine Vektoren (bis zu einer Lange von 1000)

eine deutliche Verbesserung durch die FET-Implementierung festgestellt werden, was wiederum auf

den schnelleren Aufbau der ET-Objekte zuruckzufuhren ist. Die rechte Grafik in Abbildung 6.2 zeigt

die Performance-Kurven fur den großen Ausdruck, in dem 27 Mal der selbe Vektor auftritt. Hier ist

die Leistungssteigerung der FET gegenuber der herkommlichen Implementierung deutlich sichtbar. Die

FET sowie die C-Programmierung laufen etwa zehnmal schneller als die klassische ET-Variante.

Neben diesen positiven Ergebnissen vereinfachte sich zudem die Programmierung der Parallelis-

ierung. Dazu stehen bei Verwendung des NEC-C++-Compilers (sc++) entsprechende Pragmas zur

Verfugung, mittels derer angegeben wird, welche Schleifen parallelisiert werden sollen. Lediglich bei

einfachen Schleifen ist eine automatische Parallelisierung der Schleifen moglich. Wahrend bei der Im-

plementierung der herkommlichen ET massiv mit den Pragmas gearbeitet werden musste, um eine

Parallelisierung durch den Compiler zu erreichen, ist die Vektorisierung der FET-Implementierungen

ohne zusatzliche Verwendung von Pragmas moglich.

Zusatzlich werden mit der numerischen Losung der 2D- bzw. 3D-Poisson-Gleichung auch anwen-

dungsbezogenere Problemstellungen betrachtet. Zur Diskretisierung auf Gittern bestehend aus Qua-

draten bzw. Wurfeln wird die Finite Elemente Methode verwendet, die zu Neun- bzw. 27-Punkt-

Sternen fuhrte. Die resultierenden Gleichungssysteme werden wiederum mit dem leicht parallelisierba-

ren Jacobi-Verfahren gelost. Abbildung 6.3 zeigt die zugehorigen Performance-Kurven, woraus wieder

deutlich die Leistungssteigerung der FET-Implementierung zu erkennen ist. Die FET erreichen da-

51

Page 68: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

6.3. LEISTUNGSANALYSE DER FET-IMPLEMENTIERUNGEN

bei wiederum die Performance der C-Codes, was deutlich zeigt, dass die Optimierungen die Aliase

vollstandig auflosen konnen.

,ËNGEDER6EKTOREN

NOIT

ARET)

ORPTI

E:

.%4 # #ODEOHNE%4#%4 +LASSISCHE%4&%4 &AST%4

NOIT

ARET)

ORPTI

E:

.%4 # #ODEOHNE%4#%4 +LASSISCHE%4&%4 &AST%4

,ËNGEDER6EKTOREN

Abbildung 6.3: Leistungs-Kurven auf der NEC SX-6. Numerische Losung der 2D- bzw. 3D-Poisson-

Gleichung durch Diskretisierung mittels der Finiten Elemente Methode und Anwendung eines leicht

parallelisierbaren Jacobi-Verfahrens.

Durch die FET-Implementierung konnen die Compiler also auch auf Hochleistungsrechnern die er-

wartete Performance erreichen. Dadurch konnen also FET auch fur die Problemlosung auf diesen Platt-

formen eingesetzt werden, ohne einen Leistungsverlust erwarten zu mussen. Daruber hinaus mussen

die nummerierten Variablen nicht uber den gesamten Programmcode verwendet werden, siehe dazu

Abschnitt 6.4.

Parallelisierung mittels OpenMP

Neben den Ergebnissen der Implementierungsvarianten mit automatischer Vektorisierung, werden eben-

falls die Effizienz der FET bei der Verwendung von OpenMP betrachtet. Dabei wird diese automatische

Parallelisierung auf einem AMD Opteron Cluster am Lehrstuhl Informatik 10 in Erlangen untersucht.

Dieser Rechner besteht aus neun zweifach sowie acht vierfach Knoten, jeweils mit gemeinsamen Spei-

cher, genauer beschrieben in Anhang D.2.3. Die Implementierungen werden mittels dem Intel C++-

Compiler, Version 8.1 sowie dem OpenMP-Flag zur automatischen Parallelisierung ubersetzt, wobei in

den Programmcodes die entsprechenden Pragmas fur die Anwendung von OpenMP in den Iterations-

schleifen eingefugt werden [CDK+01, EV01].

Wie bereits auf den Vektorrechnern erreichen die FET-Implementierungen bei einer Parallelisierung

mittels OpenMP die Performance der C-Programme. Diese liegt wiederum deutlich uber der erreichten

Leistung der herkommlichen ET-Versionen, wobei der Unterschied wegen der geringen Parallelisierung

weniger deutlich ausfallt als auf den Vektorplattformen.

Abbildung 6.4 prasentiert zwei Performance-Kurven, die sich auf die Ergebnisse auf einem vierfach

Knoten des AMD Opteron Clusters beziehen. Die linke Grafik zeigt dabei die Laufzeit pro Auswer-

tungsschritt des großen Ausdrucks (6.2). Dabei erreicht die FET-Implementierung eine sieben- bis

acht-mal bessere Performance. Die rechte Grafik enthalt die Laufzeitergebnisse zur Losung des zwei-

dimensionalen Poisson-Problems. Auch hier kann – trotz eines nur geringen Aliasings – eine deutliche

Verbesserung mittels FET erzielt werden.

Nach diesen Untersuchungen der Leistungsfahigkeit von FET-Implementierungen sollen nun die Pro-

grammteile eingeschrankt werden, in denen die FET benutzt werden mussen, um weiterhin einen per-

formanten Code zu erhalten.

52

Page 69: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 6. FAST EXPRESSION TEMPLATES

NOIT

ARET)

ORPTI

E:

,ËNGEDER6EKTOREN

.%4 # #ODEOHNE%4#%4 +LASSISCHE%4&%4 &AST%4

.%4 # #ODEOHNE%4#%4 +LASSISCHE%4&%4 &AST%4

NOIT

ARET)

ORPTI

E:

,ËNGEDER6EKTOREN

Abbildung 6.4: Laufzeit auf einem AMD Opteron Cluster unter Verwendung eines vierfach Knotens

mit OpenMP-Parallelisierung. Die linke Grafk stellt die Ergebnisse des Ausdrucks b =P

7

i=1a

i dar,

woraus ersichtlich wird, dass die FET-Implementierung die Performance des C-Codes erreicht. Ana-

loge Betrachtungen ergeben sich aus der rechten Kurve, worin die Laufzeiten pro Iteration fur das

zweidimensionale Poisson-Problem dargestellt sind.

6.4 Praktische Anwendung von FET

Durch das Durchnummerieren der Vektoren mittels Templates und die Kapselung aller Skalare in

gesonderte nummerierte Klassen verkompliziert sich die Verwendung von FET-Bibliotheken. Neben

der Indizierung durch den Benutzer muss dieser, um eine korrekte Implementierung zu erhalten, auch

noch darauf achten, dass die kontextbezogene Nummerierung eindeutig ist.

6.4.1 Einschrankung auf rechenintensive Programmteile

Der jeweilige Wirkungskontext der nummerierten Objekte muss sich nicht uber das gesamte Anwen-

dungsprogramm erstrecken. Die FET-Implementierungen liefern neben dem schnellen Aufbau der ET-

Objekte vor allem durch das Auflosen der Aliase einen performanteren Programmcode. Gerade diese

Aliasing-Probleme treten jedoch nur in Ausdrucken auf, in denen mehrfach die gleichen Variablen

vorkommen. Dabei handelt es sich in den meisten Fallen um die zentralen Berechnungseinheiten im

Programm, also um die Stellen, an denen sich die performance-kritischen Ausdrucke befinden. Aus

diesem Grund ist es fur den Erhalt von effizienten Programmen vollig ausreichend, die Verwendung

der FET auf die rechenintensiven Stellen im Anwendungscode zu beschranken.

Listing 6.4: Template-nummerierte Vektordatenstruktur zur eingeschrankten Verwendung in rechen-

intensiven Programmteilen.

template < i n t un ique I d >

c l a s s Fa s t Vec to r : Expr<Fas t Vecto r <un ique I d > >

. . .

F a s t Vec to r ( const Vector& vec ) : da ta ( vec . d a t a p o i n t e r ( ) ) ;

vo id r e s e t ( ) data = NULL ;

;

template < i n t un ique I d >

double∗ Fas t Vecto r <un ique I d > : : da ta = NULL ;

Basierend auf einer Implementierung, welche die herkommliche ET-Version, eine Vektorklasse im

ursprunglichen Stil von Listing 2.1 sowie eine template-nummerierte Vektorklasse umfasst, konnen

Anwendungen wie bisher programmiert werden und zusatzlich die aufwandigen Berechnungen mit

schnellen Vektoren behandelt werden. Dazu initialisiert man vor Beginn eines performance-kritischen

53

Page 70: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

6.4. PRAKTISCHE ANWENDUNG VON FET

Programmteils die nummerierbaren Variablen mittels der zugehorigen Vektordaten. Im Falle von ar-

raybasierten Datenstrukturen ist dabei keine volle Kopie der Objekte notig, lediglich die Datenzeiger

sind an den Fast Vector zuzuweisen, siehe Listing 6.4.

Nach der Initialisierung der Fast Vector-Objekte konnen die Berechnungen mit den FET durchgefuhrt

werden. Nach Ende des rechenintensiven Programmteils ist keine Ruckzuweisung der Datenzeiger notig,

da sich die Lage der Zielarrays im Speicher nicht geandert hat, lediglich der Inhalt. In folgenden

performance-kritischen Teilen konnen die bereits verwendeten FET-Vektoren wieder fur weitere Be-

rechnungen benutzt werden, da die Daten im ursprunglichen Vektor noch erhalten sind. Um jedoch

zu vermeiden mit falsch zugewiesenen Vektoren zu arbeiten, sollten nach einer solchen FET-Einheit

die statischen Datenzeiger der Fast Vector Objekte wieder auf NULL gesetzt werden ( reset -Funktion). Ein

exemplarischer Programmaufbau zu dieser eingeschrankten Anwendung findet sich in Listing 6.5.

Generell ist es ausreichend zu einer herkommlichen ET-Implementierung eine nummerierte Daten-

struktur mit den entsprechenden Schnittstellen (wie in Listing 6.4) hinzuzufugen. Sollen aber speziell

Probleme mit kleinen Datenstrukturen, z.B. Polynomen oder raumlichen Vektoren kleiner Dimension,

behandelt werden (wie vorher in Abschnitt 6.3.2 gezeigt), so hat der Aufbau der Ausdrucksbaume

durchaus Einfluss auf die Performance. In solchen Fallen ist es dann sinnvoll die vollstandige statische

FET-Implementierung neben den herkommlichen ET zu verwenden, um eine schnellere Konstruktion

der Ausdrucke zu ermoglichen. Die Beschrankung auf die rechenintensiven Programmteile kann da-

bei analog wie vorher angewandt werden. Doch mussen dann neben den schnellen Vektoren auch alle

konstanten Werte bzw. Variablen mittels entsprechender Datenstrukturen (siehe Listing 6.3) gekapselt

und nummeriert werden.

Listing 6.5: Praktische Anwendung der FET-Implementierungen an rechenintensiven Stellen.

Vector a , b , c ;

. . .

// I n i a l i s i e r u n g , e i n f a c h e Rechnungen

. . .

5 // Anfang r e c h e n i n t e n s i v e r Programmtei l

Fas t Vecto r <1> a f a s t ( a ) ;

Fa s t Vecto r <2> b f a s t ( b ) ;

Fa s t Vecto r <3> c f a s t ( c ) ;

. . .

10 // s c h n e l l e Berechnungen

. . .

a f a s t . r e s e t ( ) ;

b f a s t . r e s e t ( ) ;

c f a s t . r e s e t ( ) ;

15 // Ende r e c h e n i n t e n s i v e r Programmtei l

. . .

// we i t e r e Benutzung von a , b , c wie gewohnt , z .B .

. . .

a . p r i n t ( )

Somit kann also die Verwendung der FET-Implementierungen, die vom Benutzer selbst zu num-

merieren sind, auf die relevanten Teile der Programme eingeschrankt werden. Der restliche Teil der

Anwendungen kann mittels der herkommlichen ET wie gewohnt genutzt werden.

6.4.2 Automatisches Nummerieren

Die einzigen Veranderungen fur die Benutzer von FET-Implementierungen ergeben sich durch das

Nummerieren der Variablen, wahrend die Anwendungen der Funktionen und uberladenen Operatoren

genauso wie bei den herkommlichen ET die gewunschten mathematischen Schnittstellen liefern. Zur

einfacheren Verwendung der nummerierten Variablen ware es naturlich hilfreich, wenn die Vergabe der

Nummerierung automatisch erfolgen wurde.

54

Page 71: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 6. FAST EXPRESSION TEMPLATES

Versucht man eine solche automatische Nummerierung innerhalb von C++ mittels Templates zu

losen, stoßt man schnell an die Grenzen der Technik. Die Template-Integer mussen zur Ubersetzungszeit

feststehen und fur jede Fast Vector-Variable wird ein neuer Index benotigt. Leider konnen die Template-

Integer nicht einfach wie normale Variablen erhoht werden, denn einmal gesetzt sind sie fix. Wurde

man fur den Template-Integer nun einen konstanten statischen Integer oder einen Enumerationswert

setzen, so wurde immer der gleiche Wert fur den Template eingesetzt, da die konstanten Werte ja

nicht verandert werden konnen. Auch Traits oder die Einfuhrung von Template-Klassen anstatt Integer

konnen nicht dazu beitragen unterschiedliche Typen fur die Fast Vector-Variablen zu erzeugen. Innerhalb

eines Ausdrucks konnen neue Typen (mittels Templates, Traits, etc.) aus bestehenden Typen erzeugt

werden, die dann aber nur innerhalb des Ausdrucks oder in neu generierten Typen zur Verfugung

stehen. Die konstanten Daten von bestehenden Typen konnen nicht verandert werden, weshalb die

generierte Typinformation nur aus den neu erzeugten Typen erhalten werden kann.

Da die Nummerierung nicht innerhalb der Sprache C++ losbar ist, kann man auf die Moglichkei-

ten des Pracompilers zuruckgreifen. Hier gibt es konstante Werte, die fur verschiedene Aufrufe auch

verschiedene Werte annehmen, z.B. das Makro LINE . Fur dieses Makro setzt der Precompiler immer

die aktuelle Zeilennummer ein, und erhalt somit fur verschiedene Zeilen unterschiedliche Integerwerte.

Wenn die Fast Vector-Variablen in verschiedenen Zeilen deklariert werden, kann man mittels

Fas t Vecto r < LINE > a ;

Fas t Vecto r < LINE > b ;

die gewunschte automatische Nummerierung erhalten. Doch sind die Deklarationen der nummerierten

Variablen uber mehrere Dateien verteilt, konnen sich dennoch wiederholende Indizes ergeben. Fur diese

Problemstellung passend bietet leider nur der Visual-C++-Pracompiler ein Makro ( COUNTER ), das

bei jedem Auftreten um eins erhoht wird.

Fur andere Compiler bleibt nur die Anwendung eines externen Programms oder Skripts, welches vor

der Ubersetzung die Dateien nach den Zahlmakros durchsucht und diese durch inkrementelle Integer

ersetzt. Doch dieses Konzept der automatischen Nummerierung lost lediglich die Generierung der

Template-Integer der Fast−Vector-Variablen. Die zusatzliche Kapselung der konstanten und variablen

Werte in den FET-Anwendungen konnen dadurch nicht ersetzt werden und mussen weiterhin zusatzlich

implementiert werden.

55

Page 72: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

6.4. PRAKTISCHE ANWENDUNG VON FET

56

Page 73: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 7. ERWEITERTE METHODEN

7 Erweiterte Methoden fur ET

Nach Einfuhrung der verschiedenen Implementierungsvarianten werden in diesem Kapitel einige wei-

terfuhrende Methoden diskutiert, mittels derer die Funktionalitat von ET-Programmen verbessert

werden kann. Sofern nicht explizit angegeben, konnen die jeweiligen Techniken sowohl fur ET- als auch

FET-Implementierungen angewandt werden.

7.1 Typ-Minimierung durch Traits

Beim Entwickeln einer flexiblen Bibliothek mochte man die ET-Implementierung nicht auf einen be-

stimmten Datentyp festlegen, sondern den Grunddatentyp vom jeweiligen Anwendercode abhangig

machen. Dazu konnen in der ET-Implementierung einfach zusatzliche Template-Parameter eingefuhrt

werden, welche den verwendeten Datentyp aus der Vektorklasse bestimmen und damit an den notigen

Stellen ersetzen.

In einer so verallgemeinerten Programmierung konnen aber durchaus Grunddatenstrukturen mit

unterschiedlichen Datentypen zum Einsatz kommen, z.B. reelle und komplexe Vektoren. Um in diesem

Fall nicht alle reellen als komplexe Vektoren verwenden zu mussen, was sicherlich zu einer merkbaren

Leistungsverschlechterung fuhren wurde, kann man mittels der gezielten Anwendung von Traits eine

generalisierte Version der ET implementieren. Die notigen Typen innerhalb des ET-Codes werden

damit wieder automatisch durch den Compiler generiert und instantiiert. Als einfaches Beispiel dient

die Betrachtung der Kombinationen der Datentypen double und complex<double>. Tabelle 7.1 beschreibt

die moglichen Ergebnisse von binaren Operationen beim Aufeinandertreffen dieser beiden Typen.

Listing 7.1: Traits fur die Bestimmung des Ruckgabetyps.

template <typename L , typename R>

s t r u c t Resul tType

t ypede f s t d : : complex<double> Type ;

;

template <>

s t r u c t Resul tType<double , double>

t ypede f double Type ;

;

Dadurch kann also eine feste Struktur im Auswerten der Typen angegeben werden, die mittels dem

Traits-Mechanismus implementiert [HCKS98, LvG99, DA03] und somit wahrend der Ubersetzungszeit

Tabelle 7.1: Mogliche Typkombinationen von binaren Ausdrucken bei der Verwendung von double

und complex<double> als Grunddatentypen. Nur bei der Kombination von zwei double Werten resultiert

wiederum ein double. In den anderen drei Fallen erhalt man einen complex<double> als Ruckgabetyp.

Typ von L Typ von R Resultierender Typ

double double double

double complex<double> complex<double>

complex<double> double complex<double>

complex<double> complex<double> complex<double>

57

Page 74: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

7.1. TYP-MINIMIERUNG DURCH TRAITS

ausgewertet werden kann. Dazu wird die Klasse ResultType in Listing 7.1 eingefuhrt, die fur allgemeine

Kombinationen den Ruckgabetyp als complex<double> definiert. Nur im Spezialfall, bei dem zwei double-

Werte aufeinander treffen, wird der Ergebnistyp auf double gesetzt.

Zur Anwendung dieser Traits in den ET-Implementierungen wird in jeder Operationsklasse sowie der

Vektorklasse ein Typ R Type eingefuhrt, der den Ergebnistyp des jeweiligen Objektes definiert. Listing

7.2 zeigt die Typdefinition, mittels derer uber einen typedef dieser Ergebnistyp bestimmt wird. Hierbei

ist besonders auf die Verwendung des Schlusselwortes typename zu achten, welches dem Compiler beim

Ubersetzen mitteilt, dass es sich bei den geschachtelten Argumenten um Datentypen handelt.

Listing 7.2: ET-Implementierung fur ubersetzergenerierte Ruckgabetypen.

template <c l a s s L , c l a s s R>

c l a s s Add i t i on : pub l i c Expr< Add i t i on<L ,R> >

. . .

t ypede f typename Resul tType<typename L : : R Type ,

typename R : : R Type > : : Type R Type ;

R Type g i v e ( i n t i ) const r e t u r n l . g i v e ( i ) + r . g i v e ( i ) ;

;

template <typename baseType>

c l a s s Vector : pub l i c Expr< Vector <baseType> >

baseType ∗ data ;

. . .

t ypede f baseType R Type ;

R Type g i v e ( i n t i ) const r e t u r n data [ i ] ;

;

Damit enthalt Listing 7.2 eine ET-Implementierung, die keinen festgelegten Grunddatentyp hat, und

abhangig von den Operanden der jeweils kleinste Ruckgabetyp generiert wird. Eine solche Typminimie-

rung mittels Traits ist naturlich analog fur mehr als zwei Datentypen erweiterbar. Dafur sind lediglich

zusatzliche Spezialisierungen der Klasse ResultType notig, aus denen der Compiler die Ruckgabetypen

wahrend des Ubersetzens bestimmen kann.

Solche allgemeinen ET-Implementierungen eroffnen vielfaltige Anwendungsmoglichkeiten, weil damit

nicht nur fundamentale Typen als Grunddatenstruktur verwendet werden konnen. Prinzipiell sind viel

komplexere Datentypen einsetzbar, wie z.B. Vektoren oder Matrizen. D.h. bei einer entsprechenden

Spezialisierung der ResultType-Klasse generiert der Compiler die fur die ET-Implementierung benotigten

Instantiierungen, etwa auch fur Vector<Vector<double> >. Dazu sind neben den Spezialisierungen keine

Anderungen der ET-Implementierung notig.

Da die Komponenten von solchen geschachtelten Datenstrukturen selbst arraybasierte Typen sind,

ist es jedoch sinnvoll dafur eigene ET-Implementierungen einzufuhren, welche Operationen nicht so-

fort, sondern erst bei der endgultigen Zuweisung berechnen. Diese verzogerte Auswertung der Kom-

ponenten kann wiederum durch die Definition entsprechender Ergebnistypen mit der Ruckgabe pas-

sender Operationsobjekte realisiert werden. Da diese Operationsobjekte aber in den Auswertungsme-

thoden temporar erstellt werden (Zeilen 11 und 12 in Listing 7.3), mussen diese als volle Objekte

mittels der ET-Implementierung aus Abschnitt 5.4 abgespeichert werden. Fur eine Datenstruktur wie

z.B. Vector<Vector<double> > wurde der folgende Programmcode (Listing 7.3) die Ruckgabetypen zur

verzogerten Auswertung der Komponenten definieren.

Dabei bezeichnet Vector Expr eine zusatzliche Wrapper-Klasse fur die Ausdrucke mit Ergebnistyp

Vector<Vector<double> > und Delayed Component Addition die entsprechende Operationsklasse fur die ver-

zogerte Addition der Komponenten, die in diesem Falle vom Typ Vector<double> sind. Zur Bestimmung

der Typen der Operanden in den Zeilen 13 bis 15 werden die Traits-Implementierungen von BASE

verwendet, da ein Zugriff auf Membertypen nur uber den Klassentyp moglich ist, nicht uber einen

Referenztyp.

58

Page 75: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 7. ERWEITERTE METHODEN

Listing 7.3: ET fur verzogerte Auswertungen der Komponentenoperationen.

template <c l a s s TYPE >

s t r u c t BASE t ypede f TYPE TYPE ; ;

template <c l a s s TYPE >

s t r u c t BASE<const TYPE &> t ypede f TYPE TYPE ; ;

5

template <c l a s s L , c l a s s R>

c l a s s Delayed Component Addi t ion

: pub l i c Vector Expr < Delayed Component Addi t ion <L ,R> >

L l ; R r ;

10 . . .

t ypede f Add i t i on<typename BASE<L> : :TYPE : : R Type ,

typename BASE<R> : :TYPE : : R Type> R Type ;

R Type g i v e ( i n t i ) const

r e t u r n l . g i v e ( i ) + r . g i v e ( i ) ; // Vektoren

15

;

Insgesamt werden also zwei verschiedene ET-Implementierungen benotigt, eine fur die Komponenten

selbst und eine weitere fur die geschachtelte Datenstruktur. Damit kann je nach Typ entschieden

werden, welche Operationsklasse benutzt werden soll. Es gibt jedoch auch Moglichkeiten verschiedene

Datenstrukturen mit nur einer ET-Programmierung zu realisieren.

7.2 ET fur verschiedene Datenstrukturen

Beim Entwickeln einer vielseitigen ET-Bibliothek, in der das effiziente Operatoruberladen fur verschie-

dene Datenstrukturen angewandt werden soll, muss nicht zwingendermaßen fur jede Datenstruktur

ein separate ET-Implementierung eingefuhrt werden. Zum Beispiel besitzen die meisten mathemati-

schen Objekte die Grundrechenarten +,−,∗, und die entsprechenden Operationsklassen konnen auch

fur verschiedene Datenstrukturen verwendet werden. Dazu sind prinzipiell nur die jeweiligen Auswer-

tungsfunktionen hinzuzufugen.

Dabei kann es jedoch passieren, dass unabsichtlicherweise Objekte addiert werden, die eigentlich nicht

kombiniert werden konnen, z.B. eine Addition von Vektoren mit Matrizen. Dadurch resultieren beim

Ubersetzen verschachtelte Fehlermeldungen mit der Folge der fehlgeschlagenen Auswertungsfunktionen.

Um diese schwer verstandlichen Compilerfehlermeldungen zu vermeiden, wird – aufbauend auf Listing

5.2 – eine erweiterte ET-Implementierung vorgestellt, die Compilezeit-Fehlermeldungen verhindert und

falsche Kombinationen zur Laufzeit aufdeckt [Fur97].

Hierbei werden die Wrapper-Klasse und die Operationsklassen um je einen zusatzlichen Template-

Parameter erweitert, der den Ergebnisdatentyp enthalt, also beispielsweise Vector. Desweiteren exis-

tieren zwei Versionen des Plus-Operators, wobei nur bei gleicher Grunddatenstruktur der Operanden

ein Addition-Objekt erzeugt wird. Unterscheiden sich die Grunddatentypen jedoch, so wird nur eine

Fehlermeldung ausgegeben. Da fur den Compiler aber auch in diesem Fall ein semantisch korrektes

Programm entstehen soll, wird mittels der Failure -Klasse ein Objekt erzeugt, das die notigen Dummy-

Auswertungsfunktionen definiert. Diese werden aber wegen dem Programmabbruch im Operator nicht

aufgerufen.

Prinzipiell kann eine solche ET-Implementierung also so erweitert werden, dass sie auch fur verschie-

dene Datenstrukturen sicher benutzt werden kann. Im Grunde wird der Compiler durch den zusatzli-

chen Template-Parameter im Programmcode 7.4 dazu veranlasst, die unterschiedlichen ET-Versionen

selbst zu generieren.

59

Page 76: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

7.3. SPEICHERUNG VON ET

Listing 7.4: Programmiervariante zum Behandeln mehrerer Datenstrukturen und Laufzeitfehlermel-

dungen.

template <c l a s s E , c l a s s DataType>

s t r u c t Expr . . . ;

template <c l a s s L , c l a s s R, c l a s s DataType>

c l a s s Add i t i on : pub l i c Expr<Add i t i on <L ,R , DataType>,DataType>

5 . . . ;

template <c l a s s L , c l a s s R, c l a s s DT >

i n l i n e Add i t i on <L ,R,DT >

ope ra to r + ( const Expr<L ,DT >& l , const Expr<R,DT >& r )

r e t u r n Add i t i on <L ,R ,DT >( l , r )

10

s t r u c t F a i l u r e : pub l i c Expr<Fa i l u r e >

double g i v e ( i n t i ) const r e t u r n 0 ;

. . . // we i t e r e Dummy−Auswer tungs f unk t i onen

;

15 template <c l a s s L , c l a s s DTL, c l a s s R, c l a s s DTR >

F a i l u r e ope ra to r + ( const Expr<L ,DTL >& l , const Expr<R,DTR >& r )

s t d : : c e r r << ” Add i t i on o f i n compa t i b l e data t y pe s ! ” << s t d : : e nd l ;

e x i t (−1); r e t u r n F a i l u r e ( ) ;

7.3 Speicherung von ET

Die bisher prasentierten ET-Implementierungen sind darauf ausgelegt, die damit erstellten Ausdrucks-

baume innerhalb des semantischen Ausdrucks im Zuweisungsoperator auszuwerten. Doch bei der Pro-

grammierung einer benutzerfreundlichen und auch flexiblen ET-Bibliothek kann es durchaus wichtig

sein, dass ganze Ausdrucke spater im Programm weiter zur Verfugung stehen. Im Folgenden werden

deshalb zwei Implementierungsmechanismen zum Abspeichern von ET diskutiert, zum einen durch

Typkapselung, zum anderen mittels abstrakter Klassen.

7.3.1 Typkapselung und Formeln-Schablonen

Da die erzeugten ET-Objekte nach einer Zuweisung in eine neu angelegte Member-Variable geloscht

werden, mussen diese zur Speicherung kopiert werden, siehe auch Abschnitt 4.3. Deshalb ist eine

ET-Implementierung zu verwenden, die keine Referenzen in den Operationsklassen besitzt, sondern

volle Objekte (Listing 5.3). Damit werden bei einer Zuweisung alle Operationsobjekte kopiert, nicht

jedoch die Terminale des Ausdrucksbaumes, die explizit mittels Referenzen vom Wrapper abgeleitet

sind. Ein damit gespeicherter Ausdruck kann wie eine Formeldefinition verwendet werden, weil die darin

vorkommenden Variablen im weiteren Progammlauf veranderbar sind. Sollen jedoch auch die Variablen

selbst in die Formel kopiert werden, so ist in Listing 5.3 die Vektorklasse nicht als Referenztyp vom

Wrapper abzuleiten, sondern mittels Vector.

Der Typ eines ET-Ausdrucks wird wahrend der Ubersetzungszeit bestimmt. Daher kann einfach eine

Variable des entsprechenden Typs definiert werden.

Add i t i on <Vector , M u l t i p l i c a t i o n <Vector , Vector > > my expr = b + c ∗ d ;

Da diese Vorgehensweise sehr aufwandig und fehleranfallig ist, lasst man den Typen des Ausdrucks

uber das Makro typeof erzeugen. Die Verwendung von typeof ist zwar im C++-Standard definiert

und festgelegt, doch gibt es einige Compiler, welche die Funktionsweise dieses Schlusselwortes nicht im

vollen Umfang unterstutzen, wie etwa altere Versionen des Microsoft Visual-C++-Compilers.

Damit bei der Zuweisung eines ET-Objekts der zu speichernde Ausdruck nicht zweimal geschrieben

werden muss – bei Typ und Initialisierung – definiert man ein Makro, welches die entsprechende

Definition vornimmt.

60

Page 77: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 7. ERWEITERTE METHODEN

#de f i n e ET STORE(name , expr ) t y p e o f ( expr ) name ( expr )

ET STORE( my expr , b + c ∗ d ) ;

Soll ein ET-Ausdruck innerhalb einer neu anzulegenden Klasse gespeichert werden, so kann der Typ

der Membervariablen auf die gleiche Weise erzeugt werden. Bei der Initialisierung einer Speicherklasse

benotigt man den exakten Template-Typ fur die Membervariable. Um diesen nicht explizit angeben zu

mussen, kann man diesen wieder uber das typeof bestimmen lassen, oder man implementiert eine

entsprechende Creator-Funktion.

Listing 7.5: Speicherung von ET als Member-Variablen mit vollem Datentyp.

#de f i n e CLASS STORE(name , expr ) \

S to r a g eC l a s s< t y p e o f ( expr )> name ( expr )

template <c l a s s Expr>

c l a s s S to r a g eC l a s s

Expr expr ;

pub l i c :

S t o r a g eC l a s s ( const Expr& exp r ) : expr ( e x p r )

. . .

;

Bei Verwendung der vollstandig statischen ET-Variante (Listing 6.2) ist die gesamte Information uber

den Ausdruck bereits in den Template-Typen enthalten. Aus diesem Grund genugt es zum Speichern

von FET-Formeln, den Typ des Ausdrucks mittels eines typedef in einem neuen Typ zu kapseln.

#de f i n e FET STORE (name , expr ) t ypede f t y p e o f ( expr ) name ;

. . .

FET STORE( ex p r t y pe , b + c ∗ d ) ;

Danach kann der definierte Typ expr type bei Klassen oder Funktionen als Template-Parameter einge-

setzt werden. Daruber hinaus kann mit diesem gespeicherten Typen an jeder Stelle ein lokales Objekt

erzeugt werden, da die FET-Objekte keinerlei Parameter bei einem Konstruktoraufruf benotigen.

Listing 7.6: Anwendung von gespeicherten FET-Ausdrucken.

template <c l a s s f o rmu la type >

vo id bar ( f o rmu l a t y pe a ) . . .

. . .

bar ( e x p r t y p e ( ) ) ;

Dadurch lassen sich wiederum Formeln implementieren, indem etwa Handle-Klassen definiert werden,

die auf zentral gespeicherte Daten zugreifen. Dieses Konzept wurde unter anderem in der Bibliothek

Colsamm angewandt, um die Transformationsformeln der Finiten Elemente elegant und effizient pro-

grammieren zu konnen, siehe Abschnitt 11.4.1.

7.3.2 Abspeicherung mittels abstrakter Klassen

Die prasentierte Kapselung von ET-Objekten in Speicherklassen kann jedoch nur angewandt werden,

wenn die Anzahl der zu speichernden Objekte konstant ist, bzw. wenn die Typen der ET-Ausdrucke

bereits bei der Initialisierung der Speicherklasse bekannt sind. Soll jedoch eine dynamische Anzahl

von ET-Ausdrucksbaumen gespeichert werden, so ist es wegen der verschiedenartigen Typen der ET-

Objekte nicht moglich, ein Array fur diese Typen zu definieren. Ebenso konnen ET-Ausdrucke nicht mit

obiger Implementierung in einer bestehenden Klasse gespeichert werden, da der Typ der entsprechenden

Membervariablen beim Initialisieren der Speicherklasse noch nicht bekannt ist.

Da die ET-Objekte also nicht mit ihrem exakten Typ speicherbar sind, muss eine abstrakte Klasse

definiert werden, von welcher die Wrapper-Klasse abgeleitet wird. Dadurch konnen Zeiger der ab-

strakten Basisklasse in den Speicherklassen als Membervariablen benutzt werden, in denen dann die

61

Page 78: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

7.3. SPEICHERUNG VON ET

ET-Objekte bei der Zuweisung als neu angelegte Objekte (mittels new) gespeichert werden. Dazu sind

in der Basisklasse, der Wrapper-Klasse und den davon abgeleiteten Klassen virtuelle Destruktoren zu

definieren.

In der Basisklasse sind geeignete Schnittstellen einzufuhren, also virtuelle Funktionen (beispielsweise

zur Auswertung des Ausdrucks), die dann in der Wrapper-Klasse definiert sind. Diese im Wrapper defi-

nierten Funktionen rufen die Auswertung der ET uber den mittels CRTP gespeicherten Ausdruck auf,

und benutzen keine virtuellen Funktionen mehr. Fur eine erfolgreiche Optimierung ist aber darauf zu

achten, dass die neu eingefuhrten Auswertungsfunktionen anders benannt werden als die bestehenden

Auswertungsfunktionen in den Operationsklassen. Ansonsten kann keine der give-Funktionen wegen

der Vererbung von BaseClass mittels Inlining optimiert werden. Definiert man jedoch unterschiedliche

Funktionen wie in Listing 7.7 (give 2 und give), so konnen die Auswertungen wie erwartet optimiert

werden, lediglich am Knoten des Ausdrucksbaumes wird ein virtueller Funktionsaufruf erzeugt.

Listing 7.7: Abspeicherung von ET-Objekten mittels abstrakter Klassen.

s t r u c t BaseC la s s

v i r t u a l double g i v e 2 ( i n t i ) const = 0 ;

v i r t u a l ˜ BaseC la s s ( )

;

template <c l a s s E>

s t r u c t Expr : pub l i c BaseC la s s

. . .

double g i v e 2 ( i n t i ) ) const

r e t u r n s t a t i c c a s t <const E&>(∗ t h i s ) . g i v e ( i ) ;

v i r t u a l ˜Expr ( )

;

. . .

c l a s s S to r a g eC l a s s

BaseC la s s ∗ expr ;

pub l i c :

template<c l a s s E>

vo id sav e ( const E& e )

expr = new E( e ) ;

. . .

;

Abbildung 7.2 zeigt die Laufzeitergebnisse der verschiedenen Arten der Abspeicherung von ET im

Vergleich mit einer direkten Auswertung. Dazu wird als erste Implementierung eine Speicherung der

ET-Objekte uber abstrakte Klassen mit gleicher Auswertungsfunktion in Basisklasse, Wrapper und

Operationsklassen gewahlt. Die zweite Kurve stellt die Abspeicherung uber abstrakte Klassen mit

verschiedenen Auswertungsfunktionen dar, sowie eine Programmierung mittels Typkapselung aus dem

vorherigen Abschnitt 7.3. Die Leistungen der verschiedenen Implementierungen wird fur die Vektortria-

de (6.1) sowie einen großen Ausdruck (6.2) untersucht. Daraus ergeben sich die Performance-Nachteile

der Programmierungen mittels abstrakter Klassen, wobei die deutlichen Verluste fur die Implementie-

rung mit gleichen Auswertungsfunktionen das nicht durchfuhrbare Inlining belegen. Verwendet man

jedoch die Version mit unterschiedlich benannten give-Funktionen, so wird der Leistungsverlust fur

großere Ausdrucke geringer, da nur der erste Aufruf der Auswertung nicht optimierbar ist. Die Abspei-

cherung von ET-Objekten mittels Typkapselung liefert nahezu die gleiche Performance wie die direkte

Auswertung der ET-Ausdrucke.

Die mittels dieser Programmierweise gespeicherten ET-Objekte konnen im weiteren Programmver-

lauf wieder verwendet werden, dazu sind lediglich entsprechende Schnittstellen zu den bestehenden

Datenstrukturen zu implementieren. Dabei ist jedoch zu beachten, dass virtuelle Methoden nicht

von Member-Templates abhangig sein durfen, da der Compiler beim Ubersetzen nicht entscheiden

62

Page 79: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 7. ERWEITERTE METHODEN

,ËNGEDER6EKTOREN

:E

ITP

RO)T

ERA

TIO

N!BSTR+LASSENGLEICHE!USWERTUNGSFKT!BSTR+LASSENVERSCH!USWERTUNGSFKT%4 !BSPEICHERUNGMITELS4YPKAPSELUNG

$IREKTE%4 !USWERTUNG

,ËNGEDER6EKTOREN

:E

ITP

RO)T

ERA

TIO

N

!BSTR+LASSENGLEICHE!USWERTUNGSFKT!BSTR+LASSENVERSCH!USWERTUNGSFKT%4 !BSPEICHERUNGMITELS4YPKAPSELUNG

$IREKTE%4 !USWERTUNG

Abbildung 7.2: Performance-Vergleich der Auswertung von gespeicherten ET-Ausdrucken mit der

direkten Auswertung beim Erstellen des Ausdrucks. Dabei ist ein Leistungsverlust bei der Speicherung

mittels abstrakter Klassen zu erkennen, wobei insbesondere fur Implementierungen mit gleich benannten

Auswertungsfunktionen die Inline-Optimierung der Auswertung komplett fehlschlagt.

kann, welche Funktionen instantiiert werden mussen. Das bedeutet, dass man entweder den Template-

Typen als Template der Basisklasse selbst definiert, oder die Funktionen fur die benotigten Template-

Parameter implementieren muss. Diese sind dann auch in der Wrapper-Klasse einzubauen, nicht aber

in den Operationsklassen, da die Methoden des Wrappers nur die entsprechenden Methoden der ent-

sprechenden erbenden Operationsklasse aufrufen (Listing 7.8).

Die vorgestellten Methoden zur Speicherung von ET-Objekten bieten Moglichkeiten, Ausdrucke uber

eine Zuweisung hinaus zu verwenden. Dabei erzeugt lediglich die Abspeicherung mittels abstrakter

Klasse einen Overhead, der aber bei großen Ausdrucken bzw. bei nicht zu intensiver Nutzung gering

ausfallt. Diese Verschlechterung in der Leistung macht sich jedoch wiederum deutlicher bemerkbar,

wenn verschiedene uber abstrakte Klassen abgespeicherte Ausdrucke miteinander verknupft werden,

da hierdurch mehrere Unterbrechungen in der zu optimierenden Inlining-Kette entstehen.

Listing 7.8: Abspeicherung mit abstrakten Klassen und mehreren Ergebnistypen.

s t r u c t BaseC la s s

v i r t u a l double f oo ( ) const ;

v i r t u a l s t d : : complex<double> f oo ( ) const ;

;

template <c l a s s E>

s t r u c t Expr : pub l i c BaseC la s s

double f oo ( ) const

r e t u r n s t a t i c c a s t <const E&>(∗ t h i s ) . template foo<double >() ;

s t d : : complex<double> f oo ( ) const . . .

;

7.4 Sichere Matrix-Multiplikationen und ausdrucksabhangige

Auswertungen

Nach den bisher prasentierten Methoden zur erweiterten Anwendung der ET-Technik, wird in diesem

Abschnitt ein zunachst nicht offensichtliches Problem von ET-Implementierungen behandelt. Dazu

betrachtet man beispielsweise die Matrix-Vektor-Multiplikation

x = A · x

63

Page 80: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

7.4. SICHERE MATRIX-MULTIPLIKATIONEN

mit einem Vektor x und einer Matrix A, in der das Ergebnis also wieder dem gleichen Vektor x

zugewiesen werden soll. Durch den uberladenen Zuweisungsoperator der Vektorklasse wird zunachst

die erste Komponente ausgerechnet und zugewiesen. Doch der zweite Eintrag des Vektors x benotigt

ebenfalls die erste Komponente von x, die nun aber schon neu berechnet ist. In manchen Fallen ist das

Verwenden von Updates zwar erwunscht (z.B. Gauß-Seidel), doch bei der Berechnung von algebraischen

Problemen wird dies zu Fehlern fuhren. Da aber vom Benutzer einer ET-Bibliothek nicht verlangt

werden kann diese Fehlerquellen selbst zu vermeiden, benotigt man in diesen Fallen eine erweiterte

Implementierung im Zuweisungsoperator [DJ03].

Kommt also bei Matrix-Multiplikationen der Ergebnisvektor auch auf der rechten Seite vor – dabei

kann es sich auch um viel kompliziertere Ausdrucke als dem Obigen handeln – muss das Ergebnis

vor der Zuweisung in einem lokalen Vektor gespeichert werden. Der temporare Ergebnisvektor kann

nach der Berechnung des Resultats an den eigentlichen Vektor zugewiesen werden. Dieser zusatzliche

temporare Vektor in der Auswertung wird jedoch nur fur diese Spezialfalle benotigt, in den anderen

Fallen konnen die Berechnungen wie ublich ohne zusatzliche temporare Variablen durchgefuhrt werden.

Erweitert man die Vektorklasse um einen als Member gespeicherten Index, so kann man durch

Abfrage feststellen, ob der Index des Ergebnisvektors auch im Ausdruck der rechten Seite auftaucht. Bei

Implementierungen mittels nummerierten Vektoren existieren solche Indizes bereits, und es kann bereits

zur Ubersetzungszeit festgestellt werden, ob der Vektor der linken Seite auch im Ausdruck vorkommt.

Damit kann je nach dem, ob ein temporarer Vektor benotigt wird, eine gesonderte Implementierung

einfugt werden. Somit erhalt der Anwender in jedem Fall ein korrektes Ergebnis.

Die prasentierten Techniken zur Realisierung einer sicheren Matrix-Multiplikation leiten eine weitere

Nutzung von ET-Objekten ein, namlich die ausdrucksabhangige Auswertung. Hierbei wurde die Ent-

scheidung, welche Auswertungsvariante verwendet werden soll, zur Laufzeit getroffen. Daruber hinaus

besteht aber auch die Moglichkeit, den Zuweisungsoperator fur spezielle Ausdrucke zu uberladen.

Kann anhand des Typs eines ET-Ausdrucksbaumes bereits entschieden werden, welche Auswertungs-

methode angewandt werden soll, so kann dies durch eine zusatzliche uberladende Version des Zuwei-

sungsoperators erreicht werden. Diese wird dann durch das pattern matching zur Ubersetzungszeit fur

die entsprechenden Ausdrucke ausgewahlt.

Dies kann vor allem bei komplexeren Anwendungen der ET-Implementierung benutzt werden, um in

bestimmten Fallen eine performantere Auswertung der Ausdrucke zu erreichen. Betrachtet man dazu

die Verwendung von ET zur numerischen Losung partieller Differentialgleichungen, so sind bestimmte

Ausdrucke mittels einer gesonderten Auswertungsroutine schneller berechenbar als uber den herkomm-

lichen Weg – beispielsweise eine komplette Implementierung des Laplace-Operators im Vergleich zur

Summe der zweiten Ableitungen. Dies kann besonders auf Hochleistungsrechnern zu entscheidenden

Unterschieden in der Performance fuhren.

Durch das entsprechende Uberladen des Zuweisungsoperators konnen auch verschiedene ET-Im-

plementierungen parallel verwendet werden. Betrachten wir dazu beispielsweise die Verwendung von

vektorbasierten Datenstrukturen zur Diskretisierung von Funktionen auf zweidimensionalen Gebie-

ten. Die Berechnungen mit den Vektoren konnen dabei wie gewohnt komponentenweise durchgefuhrt

werden. Doch zur benutzerfreundlichen Initialisierung der Vektoren bzgl. des Diskretisierungsgebiets

kann eine zusatzliche ET-Implementierung eingefuhrt werden, welche durch Polynome oder trigonome-

trische Funktionen Initialisierungsausdrucke beschreibt, siehe auch [Pfl01]. Fur diese gesonderte ET-

Programmierung wird ein eigener Zuweisungsoperator mit passender Auswertungsroutine definiert. Die

notige Entscheidung, welche Zuweisung fur den aktuellen Ausdruck benotigt wird, kann der Compiler

dann anhand des Datentyps zur Ubersetzungszeit treffen.

Die prasentierten Methoden zum erweiterten Einsatz der Technik eroffnen ein weites Anwendungs-

gebiet fur ET, auch als flexible Bibliothek zum Einsatz fur verschiedene Datentypen. Der Template-

Mechanismus mit der internen Codegenerierung nimmt dem Programmierer dazu einen Großteil der

notigen Implementierungsarbeit zur Ubersetzungszeit ab.

64

Page 81: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 8. KOMPILIERZEITEN VON ET

8 Kompilierzeiten von ET

Die Leistungsfahigkeit von ET-Bibliotheken basiert auf den Optimierungen der C++-Compiler, die

vorwiegend aus der durchgangigen Typinformation der ET-Objekte resultiert. Grundsatzlich war der

Template-Mechanismus in C++ bei seiner Einfuhrung jedoch nicht fur eine derart intensive Nutzung

wie durch ET ausgelegt. Dennoch haben sich die Compilerbauer im Laufe der Zeit auf die wachsen-

de Komplexitat der Template-Konstruktionen eingestellt. Betrachtet man beispielsweise verschiedene

GNU-C++-Versionen, so ist eine (fast) stetige Verkurzung von ET-Ubersetzungszeiten zu verzeichnen.

Dennoch compilieren ET-Programme immer noch deutlich langer als vergleichbare Implementierungen

ohne ET. Da diese Zeiten fur das Compilieren von ET-Bibliotheken teilweise immens sind, werden in

vorliegenden Kapitel die Ubersetzungsdauern von ET untersucht und Programmierkonzepte prasen-

tiert, welche eine schnellere Compilierung von ET-Implementierungen ermoglichen.

8.1 Ubersetzung von ET-Programmen

Ein Großteil der fur die effiziente Berechnung von ET-Ausdrucken benotigten Optimierung wird durch

das Inlining der Auswertungsfunktionen ermoglicht. Dazu muss der Compiler mehrfach einen Pro-

grammcode erzeugen, der nach abgeschlossener Optimierung entsprechend eingesetzt wird, und da-

nach nicht mehr weiter verwendet werden kann. Doch da es sich bei den ET-Implementierungen meist

um kleine Inline-Funktionen handelt, verursachen diese Optimierungen nur einen kleinen Teil der re-

sultierenden Ubersetzungszeiten. Auch nicht-optimierte Ubersetzungen von ET-Programmen dauern

unerwartet lange, meist nur wenig kurzer als die vollstandig optimierte Compilierung. Einige Unter-

suchungen von optimierten Ubersetzungen mittels Profiling-Tools ergaben, dass bei den betrachteten

GNU- bzw. Intel-Compilern die Zeiten fur die Optimierung weniger als 15% der gesamten Uberset-

zungsdauer betrugen. Der eigentliche Aufwand beim Compilieren entsteht eher durch die geschachtelten

Template-Typen.

Betrachtet man nun die Compilierungszeiten verschiedener ET-Anwendungen, so lasst sich zunachst

feststellen, dass die Dauer der Ubersetzungen mit wachsender Tiefe der Ausdrucksbaume superlinear

zunimmt, siehe auch [MS00]. Prinzipiell dienen ET zur Generierung des anwendungsbezogenen Codes,

was zu weitaus komplexeren Programmen fuhrt, als man zunachst erwarten wurde. Durch die Ver-

wendung von Code-To-Code-Translatoren wie etwa ROSE [Qui02], kann der Programmcode mit allen

notigen Instantiierungen erzeugt und als Zwischencode gespeichert werden. Ubersetzt man nun diesen

Zwischencode, fur den der Compiler keine weiteren Instantiierungen mehr selbst generieren muss, so

reduziert sich die Ubersetzungszeit im Vergleich zum ursprunglichen Code nur dann, wenn die jeweils

aktuell benotigten Instantiierungen bereits bestehen. Steht dagegen die großte Instantiierung als erstes

beim Compilieren an, so dauert die Ubersetzung so lange wie bei dem ursprunglichen Programmcode

ohne explizite Instantiierungen. Grund dafur ist die Erzeugung der Templates, die fur die benotig-

ten ET-Ausdrucke rekursiv erfolgen muss, bis der Ubersetzer auf eine Instantiierung trifft, die bereits

existiert.

Bei einer Untersuchung der Compilierungszeiten diverser ET-Implementierungen konnen jedoch fur

alle getesteten Compilern ET-Varianten bestimmt werden, die deutlich langer compilierten als die

ubrigen. Die Ubersetzung von ET-Implementierungen mit vollen Objekten als Member-Variablen in

den Operationsklassen (Listing 5.3) dauert merklich langer als die Compilierung der gleichen Ausdrucke

mittels der anderen ET-Versionen.

65

Page 82: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

8.2. PRAKTISCHE METHODEN ZUR SCHNELLEREN COMPILIERUNG

Dazu zeigt die linke Grafik der Abbildung 8.1 die Ubersetzungszeiten der ursprunglichen Version

von Veldhuizen und der in Kapitel 5 prasentierten ET-Implementierungen mit vollen Objekten bzw.

mit Referenzen, jeweils compiliert mit dem GNU-Compiler, Version 4.1.0. Betrachtet wird dabei die

Summe von Vektoren mit komponentenweiser Auswertung

a = a + a + a + . . . + a,

welche einen linearen Ausdrucksbaum erzeugt. Die Graphik enthalt die Ubersetzungszeiten bzgl. wach-

sender Ausdruckgroßen. Die schnell ansteigenden Ubersetzungszeiten der ET mit vollen Memberob-

jekten ist auf die rekursive Bestimmung der Typgroßen zuruckzufuhren. Dies ist bei Referenzen als

Membervariablen nicht notig, da diese immer die gleiche Große besitzen.

,ËNGEDERKOMPILIERTEN!USDRàCKE

¯B

ERSE

TZU

NG

SZEI

TIN

3EK

%4 6ERSIONVON6ELDHUIZEN%4MITVOLLEN/BJEKTENIN/PERATIONSKLASSEN%INFACHE%4 6ARIANTEMIT2EFERENZEN

,ËNGEDERKOMPILIERTEN!USDRàCKE

¯B

ERSE

TZU

NG

SZEI

TIN

3EK

# #ODEOHNE%4

.AMESPACE %4OHNE7RAPPER%INFACHE%4 6ERSION

&%4 )MPLEMENTIERUNG

Abbildung 8.1: Ubersetzungszeiten des verschiedener ET-Implementierungen mit dem GNU-C++-

Compiler, Version 4.1.0. Die linke Grafik zeigt die Compilierungszeiten von ET-Varianten mit vollen

Objekten als Membervariablen in den Operationsklassen, wobei die Programmierungen von Veldhuizen,

aus Listing 5.3 mit der einfachen Programmierung mit Referenzen verglichen werden. Letztgenannte

Implementierungsvariante wird in der rechten Grafik den Versionen ohne Wrapperklasse, FET und

C-Code gegenubergestellt.

Daneben vergleicht die rechte Grafik die Compilierungszeiten der eben betrachteten einfachen ET-

Variante mit Referenzen, mit der namespace-gekapselten ET-Version, den FET und der Implementie-

rung im C-Stil. Dabei compiliert die namespace-gekapselte Version schneller als die einfache ET, da

sie keine Wrapperklasse besitzt, die ja fur jedes ET-Objekt instantiiert werden muss. Noch schneller

konnen jedoch die FET-Implementierung ubersetzt werden, da sie keinerlei Membervariablen oder Kon-

struktoren besitzt. Naturlich kann eine Implementierung im C-Stil am schnellsten ubersetzt werden,

da hier keinerlei Templates verwendet werden.

Ubersetzungen mit dem Intel-C++-Compiler liefern sehr ahnliche Ergebnisse, doch ubersetzt dieser

die Template-Codes prinzipiell schneller als die GNU-Compiler. Nach diesen allgemeinen Betrach-

tungen werden noch spezielle Implementierungsmechanismen prasentiert, mittels denen die Compi-

lierungszeiten – vorwiegend der GNU-Compiler – verkurzt werden konnen.

8.2 Praktische Methoden zur schnelleren Compilierung

Wie bereits an den Grafiken 8.1 in vorherigen Abschnitt deutlich wurde, steigt die Ubersetzungszeit bei

allen ET-Implementierungen uberlinear an, wenn auch unterschiedlich stark. Dies ist auf die Anzahl

und Komplexitaten der jeweils verwendeten Template-Klassen zuruckzufuhren, fur die der Compiler

nach einer Instantiierung auch entsprechende semantische Analysen durchfuhren muss. Fur das Erzeu-

gen des Codes und den anschließenden Uberprufungen werden beim Ubersetzen die entsprechenden

66

Page 83: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 8. KOMPILIERZEITEN VON ET

Instantiierungslisten nach bereits generierten Template-Klassen durchsucht. Die dazu notigen Verglei-

che der rekursiven Template-Listen beeintrachtigen die Ubersetzungszeit zusatzlich.

Im Folgenden werden mehrere Methoden zur Verkurzung der Compilierungsdauern von ET-Pro-

grammen zusammengefasst. Die prasentierten Techniken haben einzeln betrachtet nur eine geringe

Beschleunigung der Ubersetzungszeiten zur Folge, so dass sie durch keine zusatzlichen Performance-

Kurven belegt werden. Auch hangen die Erfolge der einzelnen Methoden vom verwendeten Compiler

und der jeweiligen Computerplattform ab.

8.2.1 Template-Anordnung in den Operationsklassen

Wie bereits in Kapitel 4.2.3 angesprochen gibt es zwei grundsatzliche Moglichkeiten die Operationsklas-

sen zu implementieren. Die bisher zuruckgestellte Variante definiert allgemeine unare und binare Ope-

rationsklassen mit je einem zusatzlichen Template-Parameter fur eine Klasse, welche die auszufuhrende

Operation kapselt (Listing 4.3).

template <c l a s s A, c l a s s Op, c l a s s B>

c l a s s B ina r y Exp r ;

Dabei ist es fur die Programmierung zunachst vollig irrelevant, in welcher Reihenfolge die Template-

Parameter angeordnet werden. Da die jeweiligen Template-Listen bei der Suche nach bestehenden

Instantiierungen in der vorgegebenen Reihenfolge durchlaufen werden, fuhrt die obige Definition der

Klasse Binary Expr dazu, dass zuerst die Typen des linken Operanden verglichen werden. Doch eine erste

einfache Unterscheidung, ob die aktuellen Templates mit bereits bestehenden ubereinstimmen ergibt

sich schneller aus dem Typ der Operation. Deshalb ist es sinnvoller, die Operation als ersten Template-

Parameter zu behandeln, und erst danach die Typen der Operanden. Dadurch wird zunachst der Typ

der Operation verglichen, welcher kein geschachtelter Typ ist – oder, zumindest nicht in dem Maße

wie die Operanden. Bei den Implementierungen mit separaten Klassen fur jede Operation tritt diese

Problematik nicht auf.

template <c l a s s Op, c l a s s A, c l a s s B>

c l a s s B ina r y Exp r ;

Zum Test, wie abhangig der verwendete Compiler von der Organisation der Template-Listen ist,

kann der Programmcode aus Listing 8.1 herangezogen werden. Darin werden zwei prinzipiell gleich

strukturierte Klassen (C Int bzw. Int C) prasentiert, die sich lediglich in der Reihenfolge von Integer

bzw. geschachteltem Template-Typ unterscheiden. Intern wird rekursiv ein Typ bestimmt, welcher

jedoch immer int ergibt.

Bei der Generierung einer Instantiierung entstehen fur das Klassen-Template C geschachtelte Typen

von C Int, die jedoch fur jede Instanz einen eigenen Template-Integer besitzen. Fur beide Versionen

werden bei den selben Template-Parametern die gleiche Anzahl an Instantiierungen erzeugt. Mittels

template c l a s s C Int<i n t ,500 > ;

kann man sich zu gegebenen Template-Parametern die notigen Instantiierungen generieren lassen.

Die resultierende Ubersetzungszeit ist fur diese Instantiierung (deutlich) langer als fur den analogen

Ausdruck der zweiten Implementierung, die zuerst den Integer als Template-Parameter besitzt:

template c l a s s I n t C <500 , i n t >;

Dabei fallt diese Differenz je nach verwendetem Compiler verschieden groß aus, abhangig davon, wie

effizient im Fall von C Int die rekursiven Templates verarbeitet werden konnen.

67

Page 84: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

8.2. PRAKTISCHE METHODEN ZUR SCHNELLEREN COMPILIERUNG

Listing 8.1: Programmcodes mit vertauschten Template-Parametern.

template <c l a s s C, i n t I>

s t r u c t C I n t

t ypede f typename C Int<C Int<C, I >, I −1>::TYPE TYPE ;

;

5

template <c l a s s C>

s t r u c t C Int<C,0>

t ypede f i n t TYPE ;

;

10

template < i n t I , c l a s s C>

s t r u c t I n t C

t ypede f typename I n t C<I −1, I n t C<I , C> > : :TYPE TYPE ;

;

15

template <c l a s s C>

s t r u c t I n t C <0,C>

t ypede f i n t TYPE ;

;

8.2.2 Balancierung der Ausdrucksbaume

In den Beispielen aus Abschnitt 8.1 wurden mit der Summe von Vektoren spezielle Probleme betrach-

tet, die zu einem linearen Ausdrucksbaum fuhren. In allgemeinen Anwendungen wird man automa-

tisch balancierte Ausdrucke haben, beispielsweise durch Multiplikation oder durch eine Klammerung.

Verursacht eine Implementierung mit großen ET-Ausdrucken eine lange Ubersetzungszeit, so kann

man diese meist durch eine passende Klammerung verkurzen. Dennoch konnen sich bei mehreren

ET-Anwendungen in einem Programm durchaus viele verschiedene Instantiierungen ergeben, so dass

hierfur die Compilierungszeit durch Klammerung kaum verkurzt werden kann.

Listing 8.2: Einfache, schneller ubersetzbare ET-Implementierung.

1 template< i n t iA , c l a s s A>

s t r u c t X

ope ra to r const A&() const r e t u r n ∗ s t a t i c c a s t <const A∗>( t h i s ) ;

;

template < i n t iL , i n t iR , c l a s s L , c l a s s R>

6 c l a s s Add : pub l i c X<i L+iR , Add<iL , iR , L ,R> >

const L& l ; const R& r ;

pub l i c :

Add( const L& l , const R& r ) : l ( l ) , r ( r )

double g i v e ( i n t i ) const r e t u r n l . g i v e ( i )+ r . g i v e ( i ) ;

11 ;

template < i n t iL , i n t iR , c l a s s L , c l a s s R>

i n l i n e Add<iL , iR , L ,R>

ope ra to r+(const X<iL , L>& l , const X<iR ,R>& r )

r e t u r n Add<iL , iR , L ,R>( l , r ) ;

16

c l a s s Vec : pub l i c X<1,Vec>

. . .

template< i n t iA , c l a s s A>

vo id ope ra to r=(const X<iA ,A>& x )

21 const A& x ( x ) ;

f o r ( i n t i= 0 ; i < n ; ++i )

da ta [ i ] = x . g i v e ( i ) ;

double g i v e ( i n t i ) const r e t u r n data [ i ] ;

26 ;

68

Page 85: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 8. KOMPILIERZEITEN VON ET

Fur solche intensiven ET-Anwendungen wird eine von Listing 5.3 abgewandelte Implementierung

prasentiert, mittels derer die Compilierungszeiten reduziert werden konnen. Listing 8.2 zeigt eine Vari-

ante, die zusatzlich zu jedem Template-Parameter, der einen geschachtelten Typen enthalten kann, ein

Integer-Template vorangestellt, der beim Durchsuchen der bestehenden Instantiierungen zuerst ver-

glichen wird. Das Template-Integer der Wrapper-Klasse wird fur Vektoren immer 1 gesetzt, bzw. bei

Operationsklassen gleich der Summe der Template-Integer der Operanden. Dadurch ergeben sich je

nach Tiefe der Operanden unterschiedliche Integer-Werte, so dass der Compiler die Instantiierungen

nur bei Ubereinstimmung dieses Integers durchsucht. Es ware anschaulicher anstatt der Summe das

Maximum zu bestimmen, doch fuhren die dazu notigen Vergleiche zu einer langeren Ubersetzungszeit.

Diese zusatzlichen Template-Integer beeintrachtigt die notwendige Zeit fur das Ubersetzen normaler

Anwendungen nicht.

8.2.3 Auslagerung von ET-Ausdrucken

Falls die Ubersetzungszeiten trotz Anwendung dieser Methoden dennoch zu lange sind, so kann man

als Anwender einer ET-Bibliothek versuchen, Teile der Berechnungen mittels ET in eine Funktion aus-

zulagern. Betrachten wir beispielsweise die Implementierung des cg-Algorithmus’ zur Berechnung der

Losung eines linearen Gleichungssystems. Verlagert man diesen Algorithmus in eine eigene Funktion

in einer separaten Datei und ubergibt der Funktion die notigen Variablen (Vektoren, Matrix, Ab-

bruchkriterien), so kann das cg-Verfahren getrennt von der eigentlichen Anwendung ubersetzt werden.

Dadurch muss die cg-Implementierung in der separaten Ubersetzungseinheit nicht bei jeder Anderung

des restlichen Anwednungscodes neu compiliert werden.

vo id cg a l go r i t hm ( Vector& x , const Matr i x& A,

const Vector& b , double e p s i l o n ) ;

Diese Methode lasst sich nur dann so einfach anwenden, wenn die Vektoren nicht selbst von Template-

Parametern abhangen. In diesem Fall mussten beim Compilieren der separaten Funktion die Instan-

tiierungen aller benotigten Typen durch explizite Instantiierung generiert werden. Sollen jedoch gan-

ze ET-Objekte ubergeben werden, kann eine Auslagerung in eine separate Compilierungseinheit nur

mittels einer abstrakten Basisklasse, wie in Listing 5.4, realisiert werden. Denn hierdurch ist die Ar-

gumentliste der Funktion unabhangig von Template-Parametern. Dies beeintrachtigt jedoch wiederum

die Leistung des resultierenden Programmcodes.

Prinzipiell existieren also viele kleine Implementierungsvarianten, mittels derer die Ubersetzungs-

zeiten von ET-Ausdrucken verkurzt werden konnen. Dies betrifft den Programmierer ebenso wie die

Anwender von ET-Biliohteken.

69

Page 86: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

8.2. PRAKTISCHE METHODEN ZUR SCHNELLEREN COMPILIERUNG

70

Page 87: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 9. ET – AUSBLICK

9 ET-Bibliotheken – Ausblick

Die Implementierungstechnik der Expression Templates ist eine hervorragende Moglichkeit effiziente

Programme unter Vermeidung von unnotigen temporaren Variablen zu realisieren. Nach ihrer Einfuhr-

ung und Verbreitung wurde die ET-Technik vor allem fur die effiziente Programmierung von benutzer-

freundlichen Schnittstellen in C++ herangezogen. Diese intensive Nutzung des Template-Mechanismus

fuhrte auch zu leistungsfahigeren Compilern, durch welche die ET-Konstrukte schneller und auch per-

formant ubersetzt und optimiert werden konnen.

Wahrenddessen wurden aber auch die noch bestehenden Mangel der Methode aufgedeckt, wie zum

Beispiel das Aliasing-Problem oder die komplizierte und oft langwierige Programmierung. Um den

Programmierern diese aufwandige Programmierung abzunehmen, wurde mit PETE eine Bibliothek

entwickelt, welche die ET-Implementierungen fur array-basierte Datenstrukturen vereinfachte. Doch

ET-Bibliotheken fur komplexere oder aufwandigere Datenstrukturen waren damit nur sehr schwer bis

gar nicht zu realisieren. Aus diesem Grund wurde mit der Entwicklung der einfachen ET eine Pro-

grammierweise eingefuhrt, mittels derer auch darin ungeubte Programmierer sehr intuitiv und ohne

großen Implementierungsaufwand die Technik fur ihre Problemstellungen verwenden konnen. Daruber

hinaus wurde mit den Fast Expression Templates eine Variante prasentiert, welche ein Auflosen des

Aliasings bei wiederholtem Auftreten von Variablen in Ausdrucken ermoglicht und so effiziente Pro-

gramme liefert. Dies macht die Implementierungstechnik, wie gezeigt, besonders auch fur Vektorrechner

und andere parallele Architekturen interessant, da die Effizienz der Programme nahezu identisch mit

der entsprechenden Programmierung in C ist. Damit erlauben FET ein effizientes objekt-orientiertes

Implementieren von Programmen auf Hoch- und Hochstleistungsrechnern.

9.1 Limitierungen von ET-Bibliotheken

Obwohl die Implementierung von ET-Programmen durch die prasentierten Methoden einfacher durch-

fuhrbar ist, konnen dennoch bei der Anwendung von ET-Bibliotheken unerwunschte Probleme entste-

hen.

9.1.1 Komplexe Fehlermeldungen

Anders als bei Bibliotheken mittels abstrakter Klassen und virtuellen Funktionen, bei denen eine falsche

Benutzung eine kurze Fehlermeldung zur Folge hat, entstehen auch bei wohlgetesteten ET-Programmen

durchaus komplexe Fehlermeldungen. Um diese zu verstehen und die Probleme in der Anwendung zu

beheben, benotigt man meist ein gewisses Verstandnis fur die verwendete Bibliothek.

Benutzt man versehentlich fur einen ET-Ausdruck Operatoren oder Funktionen, die nicht entspre-

chend uberladen sind, so wird eine umfangreiche Fehlermeldung uber die fehlende Funktion ausgege-

ben. Der Compiler listet – als Information zur besseren Fehlerbehebung – die Typen des fehlerhaf-

ten Ausdrucks auf. Und da es sich dabei selbst um geschachtelte Typen handeln kann, konnen diese

Ausdrucke sehr komplex werden. Doch dadurch, dass die in den Kapiteln 5 und 6 prasentierten ET-

Implementierungen keine unnotig mittels eines Wrappers gekapselte Ausdrucke besitzt, fallen diese

Fehlermeldungen kurzer aus als bei den ursprunglichen ET-Versionen.

Daneben ergeben sich noch viel kompliziertere Fehlermeldungen, falls die falsche Benutzung der

Bibliothek erst bei denen als inline deklarierten Funktionsaufrufen auftritt. Denn dann gibt der Com-

71

Page 88: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

9.1. LIMITIERUNGEN VON ET-BIBLIOTHEKEN

piler alle Instantiierungen des Funktionsaufrufs aus, die zu diesem Fehler gefuhrt haben, jedesmal mit

der kompletten Angabe aller aktueller Template-Parameter.

Fur eine gut anwendbare ET-Bibliothek sollten deshalb die Compiler-Fehler so weit es geht durch

Laufzeit-Fehler abgefangen werden. Im Ansatz wurde dies in Abschnitt 7.2 vorgefuhrt. Doch auf diesem

Weg kann nur ein gewisser Teil der Anwendungsfehler mittels Laufzeitfehlern abgehandelt werden.

Außerdem sollte ein Anwender uber einen fehlerhaften Code bereits beim ersten Erkennen informiert

werden, nicht erst wahrend des Programmlauf.

Prinzipiell konnen auch eigene C++-Parser implementiert werden, um einfachere Ubersetzerfeh-

lermeldungen zu erhalten, beispielsweise durch Elsa [McP04]. Mittels diesem auf dem GLR Parser

Generator Elkhound [MN04] aufbauenden C++-Parser werden u. a. Template-Implementierungen auf

Korrektheit uberpruft und bei Fehlern verstandlichere Meldung generiert, die nur die fur den Anwen-

der notigen Informationen zum Beheben des Fehlers enthalten. Doch diese mussen dann zusatzlich

zur eigentlichen Bibliothek angeboten und benutzt werden, was die Anwendung der ET-Programme

erschwert.

9.1.2 Testbarkeit von ET-Programmen

Da die ET-Implementierungen auf den Fahigkeiten des Template-Mechanismus beruhen, ergeben sich

auch die gleichen Probleme der Testbarkeit wie bei Template-Programmen. Der Compiler uberpruft

den templatisierten Code zunachst nur syntaktisch und kann eine semantische Analyse erst bei ent-

sprechenden Instantiierungen durchfuhren. Da der Compiler den templatisierten Code aber nur dann

instantiiert, wenn dieser benotigt wird, konnen fehlerhafte Implementierungen lange unentdeckt blei-

ben. Diese entstehen dann erst bei der ersten Benutzung des entsprechenden Programmteils.

Zur sorgfaltigen Entwicklung von ET-Bibliotheken sollten deshalb parallel zur Implementierung

auch die zugehorigen Testprogramme erstellt werden, welche den aktuell entwickelten Programmco-

de ausfuhren. So kann leichter sichergestellt werden, dass Teile der templatisierten Programmierung

ungetestet bleiben. Dabei muss darauf geachtet werden, dass Memberfunktionen mit Templates nicht

automatisch mit der Klasse generiert werden, sondern wiederum nur dann, wenn speziell diese Funktion

benotigt wird. Mit entsprechenden Testcodes konnen die potentiellen Fehler in ET-Implementierungen

zumindestens reduziert werden.

9.1.3 Grenzen der Optimierung

Die effizienten Programme die mittels ET erreicht werden konnen, resultieren uberwiegend aus den

Inline-Optimierungen der C++-Compiler, die wiederum nur durch die vollstandige und exakte Ty-

pinformation der ET-Objekte zur Ubersetzungszeit durchfuhrbar sind. Wie bei der Speicherung von

ET-Ausdrucken (Abschnitt 7.3) deutlich wurde, kann nur bei der durchgangigen Sicherung des ET-

Typs die ursprungliche Performance der direkten Auswertung erreicht werden. Sobald Teile dieser

Typinformation fehlen, verschlechtert sich auch die Effizienz der resultierenden Programme, da kein

vollstandiges Inlining mehr moglich ist.

Daruber hinaus konnen die ET-Ausdrucke nur durch die Definition neuer Variablen oder Typen ge-

speichert, und somit uber die Grenzen des semantischen Ausdrucks weiter verwendet werden. Daneben

sind keine ET-spezifischen Optimierungen von Objekten uber die Grenzen von Programmausdrucken

moglich. Da das Semikolon (;) sowie die geschweiften Klammern () nicht uberladbar sind, konnen

auch keine entsprechenden Optimierungen durch weitere ET-basierte Implementierungen realisiert wer-

den. Somit sind benutzerfreundliche, ausdruckubergreifende Optimierungen nur mit Einschrankungen

moglich, siehe dazu auch Abschnitt 12.2.

72

Page 89: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 9. ET – AUSBLICK

9.2 Erweiterte Anwendungsgebiete

Neben den bereits angesprochenen Moglichkeiten einer Benutzung der ET-Technik fur array-basierte

Datenstrukturen, existieren noch weitere interessante Anwendungsgebiete, die im Folgenden kurz be-

trachtet werden.

• FACT! (Functional Additions to C++ through Templates and Classes) [SS00] ist eine mittels

PETE erzeugte ET-Bibliothek zur Implementierung des Lambda-Kalkuls. Daher konnen Funk-

tionen mit der Definition entsprechender Variablenlisten in neuen Funktionen gekapselt werden,

die dann wiederum durch Einsetzen fester Argumentlisten ausgewertet werden. Ein einfaches Bei-

spiel ist die Lambda-Funktion zur Addition von zwei Werten, die in FACT! wie folgt geschrieben

werden kann, wobei a und b beliebige Objekte mit definiertem Plus-Operator sein konnen:

us ing LAMBDA: : x ;

us ing LAMBDA: : y ;

. . .

lambda ( x , y , x + y ) ( a , b ) ;

Hierbei wird die ET-Technik also zur Einfuhrung von Funktionen herangezogen, in die dann bei

der Auswertung die entsprechenden Variablen eingesetzt werden konnen.

• Eine weitere interessante Anwendung stellt die Verwendung von ET-Implementierungen zur Dif-

ferentialrechnungen von Funktionen dar. Werden die Funktionsteile (Polynome, trigonometrische

Funktionen, etc.) in Typen gekapselt, so konnen fur die, durch zugehoriges Operatoruberladen

entstehenden, ET-Ausdrucke Ableitungsregeln implementiert werden [GG]. Die Berechnungen der

Ableitungsformeln konnen durch entsprechende Typumwandlungen bereits zur Ubersetzungszeit

durchgefuhrt werden. Ahnliche und weiterfuhrende Konzepte wurden auch in Colsamm realisiert,

siehe Kapitel 11.

Daruber hinaus lassen sich ET auch noch fur die Realisierung von Schleifeniterationen heranziehen,

oder etwa zur Programmierung von Mengenalgebren (Schnitt, Vereinigung, Komplement), siehe dazu

Kapitel 12.

9.3 Abschließende Bemerkungen

Die effiziente Implementierung der mathematischen Operatoren in C++ wurde durch die Einfuhrung

der Expression Templates revolutioniert. Durch die Kapselung von Ausdrucksbaumen in templatisierten

Klassen wird ein vollstandiges Inlining zur Ubersetzungszeit ermoglicht. Die Effizienz der resultierenden

Implementierungen liegt bereits sehr nahe an der Performance vergleichbarer Programme im C-Stil.

Fur die Entwicklung von ET-Bibliotheken wurden in der vorliegenden Arbeit Implementierungsvari-

anten prasentiert, die eine einfache, kurze Programmierung der Technik zulassen. Dabei werden die zu

implementierenden Template-Konstrukte klein gehalten, so dass undurchsichtige Fehlerquellen redu-

ziert werden. Trotzdem ist dadurch weiterhin ein typsicheres Uberladen der Operatoren gewahrleistet,

so dass keine Konflikte mit bestehenden Versionen von Operatoren entstehen konnen. Dadurch besteht

auch fur Programmierer ohne tiefere Template-Kenntnisse die Moglichkeit, die ET-Technik einfach und

intuitiv implementieren.

Zusatzlich prasentiert die vorliegende Arbeit, mit den nummerierten Variablen und den Fast Ex-

pression Templates, Programmiervarianten, mit denen die bestehenden Performance-Mangel der ET-

Technik behoben werden. Auf Grund des konservativen Mechanismus zum Auflosen der Aliase, konnen

die Compiler nicht alle erforderlichen Identifizierungen der Datenzeiger durchfuhren. Durch die Zuord-

nung der Zeiger zu eigenen Klassentypen und der dadurch moglichen Deklaration als statische Zeiger,

optimieren die Compiler die ET-Anwendungen wie gewunscht. Dies macht den Einsatz der ET-Technik

73

Page 90: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

9.3. ABSCHLIESSENDE BEMERKUNGEN

auch fur Hoch- und Hochstleistungsrechner interessant, um effiziente und benutzerfreundliche Biblio-

theken ohne Performance-Verluste anwenden zu konnen.

Die Nutzung der ET-Technik benotigt eine effektive und robuste Realisierung des Template-Mecha-

nismus. Obwohl diese intensive Verwendung von Templates in C++ ursprunglich nicht beabsichtigt

war, sind die ET-Anwendungen mit den mehrfach geschachtelten Typen dennoch ohne nennenswer-

te Einschrankungen ubersetzbar. Jedoch offenbaren viele Compiler bei extremem Einsatz von ET-

Implementierungen durchaus Grenzen (siehe Abschnitt 8). Daneben verdeutlichen die bestehenden

Performance-Mangel der ET-Technik und der daraus entstandenen FET-Implementierungen die Opti-

mierungslucken der C++-Compiler. Die prasentierten Ergebnisse konnen dazu dienen, den Compiler-

bauern Hinweise fur eine verbesserte Optimierung zu bieten.

Generell stellen Expression Templates eine sehr machtige und interessante Implementierungstechnik

zum Erstellen und effizienten Auswerten von Ausdrucksbaumen dar. Die prasentierten Mechanismen

dienen als Ermutigung fur Entwickler wissenschaftlicher Bibliotheken eigene ET-Implementierungen

einzusetzen, um so die Benutzung und Anwendungssicherheit ihrer Codes zu verbessern.

74

Page 91: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

Teil III

Einsatz von ET zum Losen von

partiellen Differentialgleichungen

Page 92: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen
Page 93: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 10. FINITE ELEMENTE

10 Finite Elemente

Viele Vorgange der Natur die in Physik, Chemie oder Biologie modelliert werden, werden durch (par-

tielle) Differentialgleichungen beschrieben. Dabei sind grundsatzlich Funktionen gesucht, welche die

entsprechende Differentialgleichung zu gegebenen Anfangs- und/oder Randwerten erfullen. Einige be-

kannte Beispiele von Differentialgleichungen sind:

• Poisson-Gleichung, z.B. bei der Warmeausbreitung in einer Platte [Bra97],

• Navier-Stokes-Gleichungen, durch die die Stromungsgeschwindigkeit und die zugehorige Druck-

verteilung in sog. Newtonschen Gasen oder Flussigkeiten beschrieben werden [KA00], oder

• Maxwell-Gleichungen, mit denen die Erzeugung und die Wechselwirkung von elektrischen und

magnetischen Feldern bzw. deren Ladungen und Stromen modelliert werden [Mon03].

Ganz allgemein lasst sich eine PDG der Ordnung k in der impliziten Form

F(

x, u(x), Du(x), D2u(x), . . . , Dku(x), . . .)

= 0

darstellen, worin F eine beliebige Funktion ist, x ∈ Rd gilt und Dk die partiellen Ableitungen bis zum

Grad k bezeichnen.

Im Rahmen dieser Arbeit beschranken wir die Betrachtung auf explizite lineare PDGen 2. Ordnung,

d.h. auf Gleichungen, in denen nur Differentialoperatoren des ersten und zweiten Grades auftreten,

also [Bra97]

−n

i,k=1

∂xi

(

aik(x)∂

∂xku

)

+

n∑

i=1

bi(x)∂u

∂xi+ c(x)u = f(x), (10.1)

wobei a : Ω → Rd,d, b : Ω → Rd und c : Ω → R. In kurzerer Schreibweise lautet (10.1) wie folgt:

−∇ · (a(x)∇u) + b(x) · ∇u + c(x)u = f(x).

Je nach den Eigenschaften der Matrix a(x) werden die Differentialgleichungen (10.1) in drei Typen

eingeteilt:

• ist a(x) in jedem Punkt positiv definit, so heisst (10.1) elliptisch,

• hat a(x) einen negativen und n − 1 positive Eigenwerte, wird (10.1) hyperbolisch genannt, und

• ist a(x) in jedem Punkt semidefinit und rg(a(x), b(x)) = n, so heißt (10.1) parabolisch.

Im elliptischen Fall schreibt man kurz

Lu = f. (10.2)

Hyperbolische bzw. parabolische PDGen konnen oft (mit t als Zeitkomponente) folgendermaßen ge-

schrieben werden (L ist ellipitischer Differentialoperator):

∂2u

∂t2+ Lu = f bzw.

∂u

∂t+ Lu = f.

Da sich die Losungen solcher Differentialgleichungen nur in speziellen Fallen analytisch berechnen

lassen, greift man im Allgemeinen auf numerische Losungsverfahren zuruck. Fur hyperbolische und

77

Page 94: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

10.1. DIE FINITE ELEMENTE METHODE

parabolische PDGen werden dazu meist spezielle Diskretisierungen fur die Zeitkomponente verwendet,

z.B. explizit/implizites Euler-Verfahren oder Runge-Kutta-Verfahren. Deshalb beschranken sich die

weiteren Erlauterungen auf den elliptischen Fall.

Eine korrekt gestellte elliptische PDG 2. Ordnung besitzt zusatzlich vorgegebene Randbedingungen.

Prinzipiell unterscheidet man drei unterschiedliche Typen von Randbedingungen, namlich Dirichletsche

(D), Neumannsche (N) und Robinsche (R) Randbedingungen, die zusammen den Rand des Gebietes

Ω in disjunkte Mengen aufteilen,

δΩ = ΓD ∪ ΓN ∪ ΓR.

Dabei ist ΓD abgeschlossen. Des Weiteren konnen die Mengen auch leer sein, falls die zugehorige

Randbedingung nicht vorkommt. Damit ergibt sich folgende Problemstellung:

Lu = f, in Ω (10.3)

u = gD, auf ΓD ⊂ δΩ (10.4)

a(x) · ∂u

∂n= gN , auf ΓN ⊂ δΩ (10.5)

a(x) · ∂u

∂n− κu = gR, auf ΓR ⊂ δΩ (10.6)

Zur numerischen Losung von PDGen wird uber das Gebiet Ω ein Diskretisierungsgitter oder ei-

ne Triangulierung Ωh gelegt, aus der die Diskretisierungspunkte und Elemente entstehen, siehe auch

Abschnitt 10.1.2. Darauf aufbauend gibt es verschiedene Ansatze, um die approximative Losung der

PDG zu berechnen. Die resultierenden Gleichungssysteme konnen mittels Verfahren der numerischen

linearen Algebra gelost werden (z.B. cg-, Gauß-Seidel-, Mehrgitter-Verfahren, GMRES, ...).

Ein einfacher und intuitiver Weg, um eine PDG auf einem Gitter zu diskretisieren, ist sicherlich

die Finite Differenzen Methode (FDM). Dabei werden die in den Differentialgleichungen auftretenden

(partiellen) Ableitungen durch Differentialquotienten approximiert [Bra97]. Somit erhalt man fur jeden

Punkt des Diskretisierungsgitters einen Stern, durch den die Differentialoperatoren approximativ be-

stimmt werden. Die FDM ist jedoch nur auf strukturierte Gitter einfach anwendbar, außerdem lassen

sich inhomogene Neumannsche Randbedingungen nur sehr aufwandig realisieren. Des Weiteren stellt

die zugrunde liegende Konvergenztheorie oft zu einschrankende Anforderungen an die zu erwartenden

Losung [Bra97].

Neben der FDM gibt es noch weitere Diskretisierungsmethoden, wie etwa die Finite Volumen Metho-

de, die Randelement Methode oder die Lattice-Boltzmann-Methode. Ein sehr flexibles und weit verbrei-

tetes Verfahren zur Diskretisierung ist jedoch die Finite Elemente Methode (FEM), deren Grundlagen

und Mechanismen im Folgenden vorgestellt werden.

10.1 Die Finite Elemente Methode

Die Anwendung der FEM spaltet sich im Wesentlichen in vier Schritte auf [CSvS86]:

1. Erstellen der schwachen Form und Umwandlung in eine geeignete Bilinearform.

2. Erzeugung eines problemspezifischen Diskretisierungsgitters.

3. Wahl von geeigneten Finiten Elementen.

4. Berechnung der lokalen bzw. globalen Diskretisierungsmatrizen.

10.1.1 Die schwache Formulierung

Nach [KA00] besteht die grundsatzliche Strategie zur Gewinnung der schwachen Form einer PDG aus

den folgenden Schritten:

78

Page 95: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 10. FINITE ELEMENTE

• Erstellen der variationellen Formulierung der PDG durch Multiplikation mit Testfunktionen und

Integration uber das Problemgebiet Ω.

• Partielle Integration und Einsetzen der Randbedingungen um entsprechende Bilinearformen zu

erhalten.

• Verifikation der notigen Eigenschaften der erhaltenen schwachen Form, d.h. Elliptizitat, Stetig-

keit.

Ausgehend von der elliptischen PDG (10.2) wird die Gleichung in ihre variationelle Formulierung

umgewandelt. Es bezeichne L1loc(Ω) den Raum der messbaren Funktionen, die auf jeder kompakten

Teilmenge Ω′ von Ω integrierbar sind. Damit kann man aus dem Fundamentallemma der Variations-

rechnung [BS94] schließen, dass fur u ∈ L1loc(Ω)

Ω

uϕ dµ = 0 fur ϕ ∈ C∞0 (Ω) ⇔ u = 0 fast uberall in Ω (10.7)

gilt. Darauf aufbauend kann der Begriff der Ableitung durch die wiederholte Anwendung der partiellen

Integration zur sog. schwachen Ableitung verallgemeinert werden [GR05]. Danach ist die α-te schwache

Ableitung w (bezeichnet auch mit w := Dαu) fur u ∈ C|α|(Ω) definiert durch

Ω

uDαϕ dµ = (−1)|α|

Ω

wϕ dµ fur ϕ ∈ C∞0 (Ω).

Mittels dieser schwachen Ableitung lassen sich die sog. Sobolev-Raume Hm,p(Ω) einfuhren, welche

die Funktionen u ∈ Lp(Ω) enthalten, die m-mal schwach differenzierbar sind und schwache Ableitungen

in Lp(Ω) besitzen [Bra97]. Im Falle p = 2 schreibt man auch kurzer Hm(Ω). Die zugehorigen Normen

berechnen sich aus der Summe der Lp-Normen der einzelnen Ableitungen.

Elliptische PDGen der Form Lu = f (Gleichung (10.2)) werden nun durch Multiplikation mit Test-

funktionen v ∈ V und Integration uber das Problemgebiet Ω in ihre schwache Formulierung uberfuhrt

Ω

Lu · v dµ =

Ω

f · v dµ, fur v ∈ V.

Die Aquivalenz zur starken Formulierung (10.2) wird durch Gleichung (10.7) ersichtlich. Ausgehend

von dieser schwachen Formulierung konnen durch die Anwendung der Greenschen Formel [GR05] die

quadratischen Differentialoperatoren in Form des Laplace-Operators in das Produkt der Gradienten

umgewandelt werden. Fur u ∈ H2(Ω), v ∈ H1(Ω) gilt

Ω

−∇ · (a(x)∇u) · v dµ =

Ω

a(x)∇u · ∇v dµ −∫

ΓN∪ΓR

a(x)∂u

∂nv dσ.

Bezeichnet L0(·, ·) den Differentialoperator L in Ω nach Anwendung der Greenschen Formel, so wird

L0 definiert durch∫

Ω

Lu · v dµ =

Ω

L0(u, v) dµ −∫

ΓN∪ΓR

a(x)∂u

∂n· v dσ. (10.8)

Damit kann die schwache Form der PDG durch Einsetzen der gegebenen Neumann-Randbedingung

(a(x) ∂u∂n

= gN auf ΓN ) bzw. Robin-Randbedingung (a(x) ∂u∂n

= gR − κu auf ΓR) folgendermaßen ge-

schrieben werden∫

Ω

L0(u, v) dµ +

ΓR

κu · v dσ =

Ω

f · v dµ +

ΓN

gN · v dσ +

ΓR

gR · v dσ fur u, v ∈ V,

bzw. mit a(·, ·) : V × V → R

a(u, v) = (f, v)0,Ω + (gN , v)0,ΓN+ (gR, v)0,ΓR

fur u, v ∈ V. (10.9)

79

Page 96: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

10.1. DIE FINITE ELEMENTE METHODE

Somit treten also die Neumann- bzw. Robin-Randbedingungen ganz naturlich in der schwachen For-

mulierung der PDG in Erscheinung. Die Dirichlet-Bedingung wird erst nach einer entsprechenden

Diskretisierung der Problemstellung in die endlich-dimensionalen Variablen eingehen.

Nach diesen einfuhrenden Betrachtungen zur Herleitung der schwachen Form einer PDG wird nun

darauf aufbauend die Finite Elemente Methode erlautert. Diese basiert auf der Wahl von geeigneten

endlich-dimensionalen Funktionenraumen, sowie der Auswahl zugehoriger Basen, durch die die auftre-

tenden Differentialoperatoren approximiert werden. Dazu benotigt man zunachst eine Triangulierung

Ωh des Problemgebietes Ω.

10.1.2 Gebietszerlegungen

Das Gebiet Ω sei in N nicht-leere, abgeschlossene Elemente TiNi=1 zerlegt, wobei das Innere eines

Elementes Ti nicht leer sei und einen Lipschitz-stetigen Rand habe. Der Schnitt des Inneren zweier

verschiedener Elemente sei leer,

Ti ∩

Tj = ∅ fur i 6= j.

Besitzt die Schnittmenge zweier Elemente Punkte, Kanten oder Flachen, so sind diese Punkte, Kanten

bzw. Flachen beider Elemente [GR05]. Daruber hinaus bezeichne

hTi:= sup

|x − y|∣

∣x, y ∈ Ti

den Durchmesser eines Elements Ti und jedes Element der Zerlegung enthalte fur ein fest vorgegebenes

κ einen Kreis mit Radius ρTimit

ρTi≥ hTi

κ.

Die so erhaltene Zerlegung muss bei krummlinig berandeten Gebieten nicht exakt mit dem Gebiet

ubereinstimmen. Beschreibt sie aber das Gebiet exakt, d.h.

Ω =

N⋃

i=1

Ti,

so wird die Zerlegung konform genannt [KA00]. Gilt fur jedes Element der Zerlegung

ρTi≥ h

κ

mit einem globalen h, so heißt die Zerlegung uniform. Weiter wird die Zerlegung TiNi=1 mit Ωh

bezeichnet, falls h der maximale Durchmesser der Elemente Ti ist.

Eine Gebietszerlegung oder auch Triangulierung muss nicht aus einheitlichen Elementen (z.B. nur

Hexaedern) bestehen, sondern kann aus unterschiedlichen Elementtypen zusammengesetzt sein. Prinzi-

piell konnen auch allgemeinere Zerlegungen definiert werden, die etwa auch hangende Knoten enthalten

(d.h. Knoten, die auf der Kante eines benachbarten Elements liegen). Dadurch entstehen im Allgemei-

nen aber Nachteile bei der Gute der Approximation. Daneben konnen die Zerlegungen auch lokal

adaptiv sein, um kritische Regionen der PDGen besser darstellen zu konnen. Aufbauend auf diesen

Triangulierungen werden nun die Finite Elemente Raume definiert.

10.1.3 Finite Elemente

Mit einer Triangulierung Ωh lassen sich nach Ciarlet [Cia02] bzgl. jedes Elementes K ∈ Ωh Finite

Elemente im Rd als Tripel (K, Vh, Σ) mit den folgenden Eigenschaften definieren (I := i|1 ≤ i ≤ N):

1. K ist eine abgeschlossene Teilmenge des Rd mit einem nicht-leeren Inneren (o

K 6= ∅) und einem

Lipschitz-stetigen Rand.

80

Page 97: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 10. FINITE ELEMENTE

2. Vh ist ein Raum reellwertiger Funktionen auf dem Gebiet K.

3. Σ beschreibt eine endliche Menge linear unabhangiger Linearformen Φi, i ∈ I, welche auf der

Menge Vh definiert sind. Die Menge Σ ist unisolvent, d.h. fur jedes αi ∈ R, i ∈ I existiert eine

eindeutige Funktion v ∈ Vh mit

Φi(v) = αi, i ∈ I.

Folglich existieren Funktionen ϕi ∈ Vh, i ∈ I, mit

Φj(ϕi) = δij , fur alle j ∈ I,

so dass alle Funktionen v ∈ Vh bzgl. der Basis ϕi|i ∈ I eine Darstellung der Art

v =∑

i∈I

αi ϕi

besitzen. Hieraus folgt, dass der Funktionenraum Vh endlich-dimensional ist mit Dimension dim Vh =

N . Mittels dieser Darstellung kann die variationelle Formulierung (10.9)

a(u, v) = (f, v)0,Ω + (gN , v)0,ΓN+ (gR, v)0,ΓR

fur v ∈ V

durch Restriktion auf den endlich-dimensionalen Raum Vh und der Vertauschung von Summation und

Integration wie folgt geschrieben werden (fur alle ϕi, ϕj ∈ Vh, j ∈ I):∑

i∈I

αi a(ϕi, ϕj) = (f, ϕj)0,Ω + (gN , ϕj)0,ΓN+ (gR, ϕj)0,ΓR

. (10.10)

Dabei werden die Basisfunktionen ϕi zur Darstellung von u Ansatzfunktionen und diejenigen fur v

Testfunktionen genannt. Weiter bezeichne ID die Menge der Indizes aus I, deren zugehorige Funktionen

ϕi zur Darstellung des Dirichlet-Randes ΓD dienen, also

ID = i ∈ I | ϕi(ΓD) ) 0 .

Definiert man damit I0 := I \ ID, so konnen in Gleichung (10.10) unter Berucksichtigung der Dirichlet-

Randbedingung u|ΓD= gD die entsprechenden Zeilen des linearen Gleichungssystems gestrichen bzw.

die feststehenden Randbedingungen auf die rechte Seite geschrieben werden [BF01]. Damit ergibt sich

fur alle j ∈ I0 und ϕi, ϕj ∈ Vh

i∈I0

αi a(ϕi, ϕj) = (f, ϕj)0,Ω + (gN , ϕj)0,ΓN+ (gR, ϕj)0,ΓR

− a(ϕj , gD). (10.11)

Hierbei werden Ansatz- und Testfunktionen aus dem gleichen Funktionenraum Vh gewahlt, im Allge-

meinen jedoch konnen diese auch aus verschiedenen Raumen stammen, siehe Abschnitt 10.2.1. Daruber

hinaus kann der Finite Elemente Ansatz auch auf komplexe oder vektorwertige Ansatz- bzw. Testfunk-

tionen erweitert werden.

10.1.4 Referenzelemente und Transformationen

Zum Aufstellen einer globalen Diskretisierungsmatrix werden nach Gleichung (10.11) die lokalen Stei-

figkeitsmatrizen a(ϕi, ϕj) benotigt, die sich als Summe der elementweisen Diskretisierungssterne be-

rechnen. Es gilt

a(ϕi, ϕj) =∑

K∈Ωh

a(ϕi, ϕj)∣

Kfur i, j ∈ I,

wobei die Summe nur uber die Elemente K von Ωh zu berechnen ist, auf denen ϕi und ϕj einen ge-

meinsamen Trager besitzen. Haben die Funktionen keinen gemeinsamen Trager, so ergibt das zugrunde

liegende Integral immer null. Folglich gilt mit Sij = supp(ϕi) ∩ supp(ϕj)

a(ϕi, ϕj) =∑

K∈Sij

a(ϕi, ϕj)∣

Kfur i, j ∈ I.

81

Page 98: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

10.1. DIE FINITE ELEMENTE METHODE

Die Integrale auf einem Element K sind im Allgemeinen mittels direkter Integration nur sehr aufwandig

berechenbar. Nur bei strukturierten Triangulierungen konnen die Integrationsgrenzen ohne zusatzliche

Fallunterscheidungen bestimmt werden. Fur beliebige Elemente dagegen ergeben sich dadurch sehr

ineffiziente Algorithmen. Aus diesem Grund wird die Integration mittels einer Transformation auf

einem Referenzelement berechnet. Dazu bezeichne TK eine bijektive Abbildung des Referenzelementes

E auf das Element K,

TK : E → K.

Eine solche Transformation hangt von der Art und der Lage des Elements K ab und bildet die Eck-

punkte des Referenzelementes auf die entsprechenden Ecken von K ab. Besitzt TK im Speziellen die

Struktur TK(x) = PK0 +FK(x) mit einer linearen Abbildung FK , so handelt es sich bei der Menge der

damit erzeugten Elemente um affine Familien.

Abbildung 10.1: Transformation des Referenzelements auf allgemeine Dreiecke.

Die Funktionen auf einem allgemeinen Element K lassen sich uber die Transformation aus den

zugehorigen Funktionen auf dem Referenzelement bestimmen,

f : K → R und f : E → R, mit f = f T−1K bzw. f = f TK .

Durch die Transformation werden somit Funktionen auf K durch Funktionen auf E dargestellt. Die

transformierten Ableitungen mussen zusatzlich durch eine entsprechende Multiplikation mit der Jacobi-

Matrix DTKvon TK bzw. DT−1

Kvon T−1

K angepasst werden. Dies kann einfach durch die Anwendung

der Kettenregel nachgewiesen werden,

∇f = ∇(

f T−1

K

)

=(

∇f T−1

K

)

·DT−1

K.

bzw.

∇f = ∇ (f TK) = (∇f TK) · DTK

Gleiches gilt auch fur die Beziehung zwischen den Richtungsvektoren a und a der jeweiligen Koordi-

natensysteme von E bzw. K:

a = a ·DT−1

Kbzw. a = a ·DTK

Prinzipiell ist dabei zu beachten, dass die Ableitung DT−1

Kvon T−1

K aus der zugehorigen Jacobi-

Matrix von TK berechnet werden kann. Das bedeutet, dass die die Umkehrabbildung T−1

k nicht be-

stimmt werden muss, was auch nicht immer moglich ist. Da die Abbildung TK nach Voraussetzung auf

E bijektiv ist, kann nach dem Umkehrsatz [Heu98] gefolgert werden:

DT−1

K(x) = D−1

TK

(

T−1

K (x))

.

Diese Beziehungen werden nun bei der Transformation der Integranden im Koordinatensystem K

auf die entsprechenden Integranden bzgl. E angewandt. Danach ergibt die Substitutionsregel [Heu98]

82

Page 99: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 10. FINITE ELEMENTE

Abbildung 10.2: Abbildung von Richtungen im Referenzelement E in das allgemeine Element K.

durch Einsetzen von x := TK(x) und der entsprechenden Multiplikation mit der Determinanten der

Jacobi-Matrix ∫

K

g(x) dµK =

E

G(TK(x)) det (DTK(x)) dµE ,

wobei g den ursprunglichen Integranden auf K und G den transformierten Integranden ebenfalls auf K

bezeichne. Ahnliches gilt auch fur die Berechnung von Rand- bzw. Oberflachenintegralen. Ist S ⊂ R3

eine Oberflache und ΦS : EB ⊂ R2 → S eine Parametrisierung der Flache EB uber dem zweidimensio-

nalen Referenzelement, so berechnet sich das Oberflachenintegral durch:∫

S

g(x) dσ =

EB

G(ΦS(x))

∂x1

ΦS(x) × ∂

∂x2

ΦS(x)

dµEB.

Außerdem gilt im Falle eines Randes S ⊂ R2 mit der Parametrisierung ΦS : [0, 1] → S uber dem

Einheitsintervall die Beziehung∫

S

g(x) dσ =

∫ 1

0

G(ΦS(x))∣

.

ΦS(x)∣

∣ dx

Durch diese Substitutionen konnen die Integrale mittels der Funktionen auf den entsprechenden

Referenzelementen berechnet werden, z.B. fur die schwache Formulierung des Laplace-Operators:∫

K

∇ϕi(x) · ∇ϕj(x) dµK =

=

K

∇ϕi

(

T−1

K (x))

· D−1

TK(T−1

K (x)) · D−TTK

(T−1

K (x)) · ∇ϕj

(

T−1

K (x))

dµK

=

E

∇ϕi(x) · D−1

TK(x) · D−T

TK(x) · ∇ϕj(x) det (DTK

(x)) dµE .

Die vorher angesprochenen Transformationen der affinen Familien ergeben sich nur in besonderen

Fallen, wie beispielsweise bei Dreiecken, Parallelogrammen, Tetraedern oder Parallelepipeden. Fur

allgemeinere Geometrien oder auch fur isoparametrische Ansatze ergeben sich keine affin-linearen For-

meln. Bei isoparametrischen Elementen werden an den Seiten (bzw. Flachen) zusatzliche Transforma-

tionspunkte definiert, mittels derer die Abbildung krummlinige Rander besser approximieren kann.

Abbildung 10.3 zeigt die Transformation eines isoparametrischen Dreiecks-Elements mit einer krumm-

linigen Kante, generell konnen aber auch mehrere krummlinige Kanten vorkommen.

Neben der Lage des Elements K hangt die Transformationsformel noch von der Nummerierung

der abgebildeten Punkte ab. Betrachtet man beispielsweise die Transformation von isoparametrischen

Dreieckselementen wie in Abbildung 10.3, so lautet die zugehorige Formel [GR05]:

TK(x, y) = PK0 +

(

PK1 − PK

0

)

x +(

PK3 − PK

0

)

y +(

4PK2 − 2

(

PK1 + PK

3

))

xy.

Bei Verwendung einer anderen Nummerierung der Punkte in den Elementen, sind der Transformati-

onsformel die entsprechenden Punkte zu vertauschen.

Mit den prasentierten Mechanismen konnen die Integrale auf einem allgemeinen Element K aus den

Basisfunktionen auf dem Referenzelement sowie der Abbildung TK und deren Ableitungen berech-

net werden. Zur einfachen und effektiven Durchfuhrung der Integration uber den Referenzelementen

verwendet man numerische Quadraturverfahren.

83

Page 100: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

10.2. EINIGE FINITE ELEMENTE APPROXIMATIONEN

Abbildung 10.3: Transformation des Referenzelement E auf ein isoparametrisches Dreieck mit einer

krummlinigen Kante.

10.1.5 Numerische Quadratur

Die analytische Berechnung der transformierten Integrale uber dem Referenzelement gestaltet sich ins-

besondere fur nicht-affinlineare Transformationen als schwierig. Denn diese besitzen keine konstanten

Ableitungen, so dass die Jacobi-Determinante ebenfalls nicht konstant ist. In der Ableitung der Umkehr-

abbildung konnen dabei gebrochen-rationale Funktionen entstehen. Aber auch bei gebrochen-rationalen

oder trigonometrischen Basisfunktionen konnen die zugehorigen Stammfunktionen nur aufwandig oder

uberhaupt nicht bestimmt werden.

Aus diesen Grunden verwendet man numerische Quadraturverfahren, mittels derer eine approxi-

mative Berechnung der Integrale durch Auswertung der Integranden an bestimmten Stutzstellen mit

entsprechender Gewichtung moglich ist. Eine besonders effiziente Methode hierfur ist das Gauß’sche

Quadraturverfahren [SB02], da es mit einer geringen Anzahl an Auswertungen der Integranden aus-

kommt. Allgemein ist

S

f(x) dµ ≈q

j=1

χjf(ξj),

wobei χj das zu der Stutzstelle ξj gehorige Gewicht bezeichnet. Dazu werden zu einer Gewichtsfunktion

n orthogonale Polynome benotigt. Die Nullstellen des n-ten Polynoms bilden dann genau die Stutz-

stellen des entsprechenden Quadraturverfahrens vom Grad n. Diese Quadraturverfahren berechnen die

Integrale fur Polynome vom Grad 2n − 1 exakt. Dies ermoglicht also mit wenigen Auswertungen des

Integranden eine exakte Integration von Polynomen von kleinen Grad, und liefert auch fur andere

Funktionen gute Approximationen.

Fur Quadrate bzw. Wurfel konnen die Gauß-Punkte und Gewichte uber die Tensorprodukte der

eindimensionalen Stutzstellen und Gewichte berechnet werden. Dagegen werden fur Dreiecke oder

Tetraeder eigens berechnete Gauß-Punkte benotigt, da hier angepasste orthogonale Polynome zu ver-

wenden sind. Die entsprechenden Werte und Gewichte konnen aus der Literatur entnommen werden,

siehe z.B. [SB02, JL01].

10.2 Einige Finite Elemente Approximationen

Wie bereits erwahnt basieren die verschiedenen Finiten Elemente Ansatze auf der Wahl endlich-

dimensionaler Funktionenraume Vh. Im Folgenden werden einige der gangigen Kriterien zur Wahl

dieser Funktionenraume zusammengefasst.

84

Page 101: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 10. FINITE ELEMENTE

10.2.1 Konforme Finite Elemente

Wird der endlich-dimensionale Raum der Basisfunktionen als Teilmenge von V gewahlt, so ubertragen

sich die darin gultigen Eigenschaften auf den kleineren Ansatzraum Vh ⊂ V [GR05]. Dies gilt damit

auch fur die Bilinearformen der schwachen Formulierung, wenn die zugrunde liegenden Integrale exakt

berechnet werden.

Im Falle einer V -elliptischen Bilinearform a(·, ·) existiert nach dem Lemma von Lax-Milgram [BS94]

fur jedes f eine eindeutige Losung uh. Falls Hm0 (Ω) ⊂ V ⊂ Hm(Ω) ist, gilt fur den Approximationsfehler

nach dem Lemma von Cea [Bra97] die folgende Abschatzung:

||u − uh|| ≤M

γinf

vh∈Vh

||u − vh||.

Entsprechende Schranken fur den Interpolationsfehler ergeben sich beispielsweise aus dem Bramble-

Hilbert-Lemma [Cia02]. Falls die Raume Vh ⊂ V asymptotisch dicht in V gewahlt werden, kann jede

Funktion v ∈ V beliebig genau durch Funktionen uh ∈ Vh approximiert werden [GR05].

Diese Ansatze werden fur symmetrische Bilinearformen auch als Ritz-Verfahren bezeichnet, wobei

uh als Losung des Minimierungsproblems in Vh angesehen wird. Im allgemeinen Fall spricht man von

Galerkin-Verfahren oder konformen FEM und betrachtet die endlich-dimensionale Variationsgleichung

(10.10) als direkte Diskretisierung der ursprunglichen schwachen Formulierung (10.9). Werden dabei

die Ansatzfunktionen u ∈ Vh und die Testfunktionen v ∈ Wh aus verschiedenen, N -dimensionalen

Raumen Vh, Wh ⊂ V gewahlt, so spricht man auch von Petrov-Galerkin-Verfahren [ZT00a].

Das bekannteste Beispiel konformer Finiter Elemente fur stetige Bilinearformen sind lineare Ansatz-

funktionen. Diese sind an einer Ecke des Elements eins und verschwinden allen anderen Ecken.

10.2.2 Nichtkonforme Finite Elemente

Bei gewissen Problemstellungen ist es sinnvoll, die Ansatzfunktionen und Testfunktionen aus einem

Raum zu wahlen, der nicht Teilmenge von V ist, also Vh 6⊂ V . Daneben kann es notig sein, die

Bilinearform a(·, ·) durch ah(·, ·) zu approximieren. Eine solche nichtkonforme Diskretisierung ist unter

anderem in den folgenden Fallen sinnvoll [GR05]:

• wenn die Wahl eines Funktionenraumes Vh ⊂ V zu aufwandig ist (z.B. bei PDGen hoherer

Ordnung),

• wenn die Bilinearformen bzw. die Integrale nur naherungsweise berechnet werden konnen,

• wenn inhomogene Randbedingungen oder krummlinige Rander von Ω keine exakte Darstellung

im diskretisierten Problem erlauben.

Die Konvergenz dieser nichtkonformen Finiten Elemente wird durch die Lemmas von Strang geliefert,

welche in der Abschatzungen des Fehlers zusatzlich die approximierende Bilinearform ah(·, ·) bzw. den

Konsistenzfehler berucksichtigen [GR05]. Ein sehr bekanntes Beispiel nicht-konformer Finiter Elemente

in 2D sind die Crouzeix-Raviart-Elemente [Bra97]. Diese Formfunktionen sind auf jedem Element linear

und besitzen nur Stetigkeit in den Seitenmittelpunkten. Die dadurch zusammengesetzten Funktionen

vh ∈ Vh sind im Allgemeinen nicht stetig auf Ω.

10.2.3 Gemischte FEM

Eine weitere Kategorie der Finiten Elemente Ansatze bilden die Diskretisierungen von partiellen Dif-

ferentialgleichungen unter Nebenbedingungen [BS94]. Diese Nebenbedingungen konnen etwa aus den

Dirichlet-Randbedingungen hervorgehen oder beispielsweise aus der zusatzlichen Inkompressibilitats-

bedingung des Stokes-Problem entstehen. Prinzipiell sucht man hierbei die Losung (u, p) ∈ V × W

85

Page 102: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

10.3. FE-SOFTWARE

vona(u, v) + b(v, p) = (f, v) fur alle v ∈ V,

b(u, w) = (g, w) fur alle w ∈ W,(10.12)

wobei a(·, ·) : V × V → R und b(·, ·) : V × W → R gegebene stetige Bilinearformen bezeichnen.

Die Funktionenraume Vh und Wh werden im Allgemeinen nicht identisch gewahlt, da sonst in vielen

Fallen die Nebenbedingung zu stark in die Diskretisierung einfließt [Bra97, ZT00b]. Dabei entstehen

je nach Wahl der Raume Vh bzw. Wh konforme oder nichtkonforme Finite Elemente Ansatze. Zur

generellen Konvergenz der Verfahren spielt die Babuska-Brezzi-Bedingung eine wichtige Rolle, die eine

abgestimmte Wahl der Funktionenraume Vh und Wh fordert [GR05].

Bekanntes Beispiel ist hierbei etwa das Taylor-Hood-Element [BS94] zur Diskretisierung der Stokes-

Gleichungen. Dabei werden fur die Geschwindigkeiten quadratische Polynome, fur den Druck jedoch

nur lineare Polynome gewahlt.

10.2.4 Vektorwertige Finite Elemente

Eine letzte Klasse Finiter Elemente, die hier erwahnt werden soll, bilden die vektorwertigen Finiten Ele-

mente. Die Ansatz- bzw. Testfunktionen mussen nicht zwingend Skalarfelder sein, sondern konnen auch

– wenn der Problemstellung entsprechend – vektorwertige Funktionen sein. Dies ist z.B. bei den Stokes-

Gleichungen der Fall, oder bei der Behandlung der vektoriellen Helmholtzgleichung. Dabei werden die

Ansatz- bzw. Testfunktionenraume oft mit Zusatzbedingungen gewahlt, wodurch die Funktionen be-

stimmte Nebenbedingungen per Definition erfullen. Werden auf diese Raume konforme FE-Ansatze

angewandt, kann die Nebenbedingung bei der Diskretisierung weggelassen werden [Mon03, GR05].

Doch die Gestaltung solcher konformer FEM-Diskretisierungen, also die Wahl endlich-dimensionaler

Funktionenraume, welche die Nebenbedingung erhalten, erweist sich als nicht-trivial [Mon03]. Dazu

werden spezielle Finite Elemente benotigt, welche beispielsweise durch eingeschrankte Flussrichtungen

bzgl. der zugrunde liegenden Elementgeometrien die Eigenschaften der Ausgangsraume erhalten [Jin02,

Mon03]. Bekannt sind hier vor allem die Nedelec-Elemente oder auch die Elemente von Raviart und

Thomas. Dazu zeigt die Abbildung 10.4 die Nedelec-Kanten-Elemente fur einen divergenz-konformen

FE-Ansatz. Die Pfeile auf den Kanten deuten die einzelnen Basisfunktionen an, die nur entlang einer

Kante eine Tangential-Komponente besitzen. Entsprechende Elemente lassen sich auch fur Vierecke

bzw. Hexaeder konstruieren.

Abbildung 10.4: Kantenelemente in 2D und 3D. Die drei bzw. sechs Basisfunktionen besitzen nur

eine Tangential-Komponente entlang einer Kante, was durch die Pfeile dargestellt wird.

10.3 FE-Software

Wie aus diesen teilweise sehr aufwandigen Ansatzen deutlich wird, benotigt eine flexible, computer-

gestutzte Realisierung Finiter Elemente Diskretisierungen effiziente Implementierungen der zugrunde

86

Page 103: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 10. FINITE ELEMENTE

liegenden mathematischen Berechnungen. Da die Finite Elemente Methode auch in der industriel-

len Simulation immer mehr Anwendung findet, existieren eine Reihe kommerzieller Software-Pakete,

beispielsweise ANSYS, ABAQUS oder Diffpack [Lan02].

Daneben wurden eine Reihe frei verfugbarer Software-Bibliotheken entwickelt, wie etwa ExPDE

[Pfl01], Overture [Hen02, BCHQ97] oder ALBERTA [SS04]. Diese Programmpakete verknupfen die FE-

Implementierungen mit einer Reihe von typischen Datenstrukturen bzw. Diskretisierungsgittern. Dazu

werden auch entsprechende Loser oder Schnittstellen angeboten, um auf die diskretisierten Gleichungen

entsprechende Losungsverfahren anwenden zu konnen.

Doch gerade in der Forschung, wie etwa bei der Untersuchung effizienter (paralleler) Datenstruk-

turen oder der Suche nach problemspezifischen Approximationsansatzen, werden oft Finite Elemente

Diskretisierungen ohne zugrunde liegende Datenstrukturen benotigt.

87

Page 104: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

10.3. FE-SOFTWARE

88

Page 105: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

11 Colsamm - Effiziente Berechnung von

FE-Matrizen

Die numerische Losung von partiellen Differentialgleichungen mittels der Finiten Elemente Metho-

de teilt sich nach dem vorherigen Kapitel in mehrere Schritte auf. Der FEM-spezifische Diskreti-

sierungsschritt besteht dabei im Berechnen und Assemblieren der globalen bzw. lokalen Diskretisie-

rungsmatrizen. Dabei birgt dieses Aufstellen der Diskretisierungsmatrizen vor allem fur Anwender

aus nicht-mathematischen Gebieten einige technische Realisierungshurden. In einfachen Fallen, al-

so bei strukturierten Gittern und positionsunabhangigen Diskretisierungssternen, ist das Aufstellen

der Matrizen ohne Transformationen oder aufwandige Integrationen moglich. Doch bei ortsabhangi-

gen Operatoren, unstrukturierten Gittern oder hohergradigen Basisfunktionen sind die Integrale der

schwachen Formulierung uber eine Transformation auf ein Referenzelement und einer numerischen

Integration zu bestimmen (Abschnitte 10.1.4 und 10.1.5). Die dazu erforderlichen Berechnungen fur

die transformierten Differentialoperatoren erschweren die Implementierung von solchen allgemeineren

FEM-Diskretisierungen zusatzlich. Besonders dann, wenn die Anwender eigentlich an der praktischen

Verwendung der FEM interessiert sind und nicht an der Programmierung der zugrunde liegenden ma-

thematischen Details. Dabei entstehen oft sehr problembezogene und unflexible Implementierungen, die

nur schwer verallgemeinert und portiert werden konnen. Daruber hinaus benotigen die mathematischen

Methoden eine leistungsstarke Realisierung, da diese beim Aufstellen der Diskretisierungsmatrizen sehr

intensiv benutzt werden.

11.1 Grundidee und Programmstruktur

Ziel bei der Entwicklung von Colsamm war eine effiziente, flexible und benutzerfreundliche Biblio-

thek zur Berechnung Finiter Elemente Diskretisierungen. Dabei sollte ein kompaktes Programmpa-

ket entstehen, das mit minimalen Schnittstellen und festem Funktionsumfang moglichst intuitiv in

C++-Programmen fur numerische FE-Approximationen genutzt werden kann. Insbesondere sollten

keine Einschrankungen auf die Art oder Implementierung der Diskretisierungsgitter und eingesetz-

ter Losungsverfahren entstehen. Die Bibliothek arbeitet deshalb ohne jegliche Informationen uber die

Verknupfungen im zugrunde liegenden Diskretisierungsgitter. Aus diesem Grund konnen innerhalb

Colsamm die berechneten lokalen Steifigkeitsmatrizen nicht zu den globalen Diskretisierungsmatri-

zen assembliert werden. Diese sind vom Anwender selbst zusammenzustellen. Abbildung 11.1 stellt

strukturell die numerische Losung partieller Differentialgleichungen dar und zeigt die Verwendung von

Colsamm zum Berechnen der lokalen Diskretisierungsmatrizen durch die Iteration uber die Elemente

des Gitters.

11.1.1 Programmablauf

Die Benutzung von Colsamm ist neben der Benutzerfreundlichkeit vor allem auch auf hohe Effizienz

ausgerichtet. Aus diesem Grund ist der Programmablauf so strukturiert, dass moglichst keine unnotigen

Berechnungen durchgefuhrt werden mussen. Dazu ist die Verwendung von Colsamm in drei Einheiten

aufgebaut.

89

Page 106: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.1. GRUNDIDEE UND PROGRAMMSTRUKTUR

Abbildung 11.1: Strukturelle Darstellung der numerischen Losung von PDGen mit der Finiten Ele-

mente Methode unter Verwendung von Colsamm.

Die zum Erstellen der lokalen Steifigkeitsmatrizen benotigten Integrale werden mittels Gaußqua-

dratur uber dem Referenzelement berechnet. Diese Integrale bestehen aus den Kombinationen der

Basisfunktionen auf dem Referenzelement und der Transformation fur das aktuelle Element. Die Ba-

sisfunktionen werden beim Anlegen eines Finiten Elements gesetzt. Dabei werden die Basisfunktionen

und deren Ableitungen an den Gaußpunkten auf dem Referenzelement ausgewertet, und diese Daten

werden abgespeichert. Dabei handelt es sich um kleine Datenmengen, denn pro Basisfunktion sind

dabei hochstens vier Werte fur jeden Gaußpunkt zu speichern. Diese Werte mussen fur ein Finites

Element nur einmal bestimmt werden.

Nach dieser Initialisierung werden in der Iteration uber die Elemente des Diskretisierungsgitters die

Koordinaten des aktuellen Elements gesetzt. Diese Daten werden verwendet, um die Transformation

und die zugehorige Jacobi-Matrix ebenfalls an den Gaußpunkten zu berechnen und abzuspeichern.

Zusatzlich wird aus den Ableitungen die Jacobi-Determinante berechnet. Insgesamt handelt es sich

dabei ebenfalls um geringe Datenmengen, jedoch mussen diese Berechnungen fur jedes Element neu

durchgefuhrt werden. Sind auf einem Element aber mehrere Integrationen durchzufuhren, so konnen

die gespeicherten Daten wieder verwendet werden.

Zuletzt werden bei der numerischen Quadratur der schwachen Formulierung die gespeicherten Werte

der Funktionen an den Gaußpunkten entsprechend dem Integranden kombiniert und daraus das Integral

berechnet. Diese Integrale sind fur alle Kombinationen von Basisfunktionen zu bestimmen. Abbildung

11.2 zeigt anschaulich diesen Programmablauf zur Berechnung der lokalen Diskretisierungsmatrizen

mittels Colsamm.

Fur die entsprechende Festlegung der Schnittstellen und des Funktionsumfangs wurde die bereits

in Abschnitt 10.1.3 aufgefuhrte klassische Definition von Ciarlet [Cia02] herangezogen. Diese mathe-

matische Definition wird etwas anwendungsorientierter formuliert. Danach hat ein Finites Element

(K, P, Σ) die folgenden Eigenschaften:

• K ⊂ Rn ist ein Element mit nicht-leerem Inneren und einem Lipschitz-stetigem Rand. In den

90

Page 107: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

Abbildung 11.2: Programmablauf von Colsamm zur Berechnung der lokalen Diskretisierungsmatrizen.

Anwendungen sind die Elemente K meist Polyeder im Rn, oder krummlinig berandete Polyeder

(isoparametrische Elemente).

• P ist ein Funktionenraum, der durch eine Menge von Basisfunktionen definiert ist. In vielen

Anwendungen sind dies reellwertige Polynome, es konnen jedoch auch trigonometrische oder

komplexwertige Funktionen eingesetzt werden.

• Die Freiheitsgrade (bei Ciarlet erklart durch lineare Funktionale) lassen sich mittels Basisfunk-

tionen auf einem Referenzelement definieren. Von diesem ausgehend konnen alle erforderlichen

Funktionen auf den allgemeinen Elementen durch entsprechende transfromationsabhangige Um-

formungen bestimmt werden.

Aus einer gegebenen partiellen Differentialgleichung, bzw. aus dem zugrunde liegenden Diskretisie-

rungsgitter, ergeben sich noch weitere, fur die einzelnen Finiten Elemente wichtige, Informationen.

Dies sind

• die Dimension des Finiten Elements,

• die Struktur bzw. Geometrie des Referenzelements,

• die Anzahl der Ecken des Finiten Elements die zur Bestimmung der Transformation benotigt

werden, und

• die Unterscheidung zwischen inneren Elementen bzw. Randelementen.

Da diese problemspezifischen Parameter der Finiten Elemente zum Teil unterschiedliche Berech-

nungsmechanismen zur Folge haben, wurde Colsamm als Template-Bibliothek konstruiert. Genauere

Erlauterungen zur zugrunde liegenden Programmstruktur, sowie zu wichtigen Implementierungsdetails

von Colsamm sind im Anhang B zusammengestellt.

In den folgenden Abschnitten werden die Schnittstellen und deren Verwendung genauer betrachtet

und diskutiert. Zunachst wird ein einfaches Beispiel der grundsatzlichen Anwendung von Colsamm zur

Erstellung der Diskretisierungsmatrizen prasentiert.

11.2 Assemblierung von Diskretisierungsmatrizen

Ausgehend von der schwachen Formulierung (10.11) werden zur Berechnung der globalen Diskretisie-

rungsmatrizen die lokalen Sterne benotigt. Diese berechnen sich aus den jeweiligen Bilinearformen bzw.

91

Page 108: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.2. ASSEMBLIERUNG VON DISKRETISIERUNGSMATRIZEN

den zugrunde liegenden Integralen auf den einzelnen Elementen. Da diese Integrale nur dann von Null

verschieden sind, wenn die Basisfunktionen ϕi und ϕj einen gemeinsamen Trager besitzen, kann die In-

tegration auf die Summe uber die im gemeinsamen Trager befindlichen Elemente eingeschrankt werden.

Also folgt z.B. fur L0(·, ·), dem Integranden aus Gleichung (10.8), mit Sij = supp(ϕi) ∩ supp(ϕj)

Ω

L0(ϕi, ϕj) dµ =∑

K∈Sij

K

L0(ϕi, ϕj) dµ.

Analoges gilt fur die Berechnung der weiteren Integrale bzw. der Randintegrale. Wahrend diese lokalen

Sterne mittels Colsamm berechnet werden konnen, sind die globalen Diskretisierungsmatrizen durch

den Anwender selbst zusammenzusetzen. Je nach Trager der Basisfunktionen, die von der Art, Lage und

Nummerierung der Freiheitsgrade sowie vom Diskretisierungsgitter selbst abhangen, sind die Werte der

lokalen Steifigkeitsmatrizen auf die entsprechenden Positionen in den globalen Matrizen zu addieren.

Mittels Colsamm werden also die elementweisen Integrale der Form

K

L0(ϕi, ϕj) dµ,

berechnet, wobei K die Elemente des Gitters durchlauft. Diese Integrale sind nur fur solche Elemente

zu berechnen, auf denen der gemeinsame Trager der aktuellen Basisfunktionen ϕi bzw. ϕj nicht leer

ist. Die Schnittstelle von Colsamm baut dabei auf der schwachen Formulierung einer PDG auf, um

eine besonders benutzerfreundliche und intuitive Anwendung zu ermoglichen.

Als einfuhrendes Beispiel dient die schwachen Formulierung des Poisson-Problems in 3D auf einem

Tetraedergitter mit der variationellen Form des Laplace-Operators

K

∇ϕi · ∇ϕj dµ,

wobei K ein beliebiger Tetraeder des Diskretisierungsgitters sei. Weiter werden die Koordinaten des

i-ten Eckpunktes des Tetraeders mit PKi = (PK

i,x, PKi,y, PK

i,z), i ∈ 0, 1, 2, 3 bezeichnet. Ein Tetraeder-

Element mit linearen Basisfunktionen wird durch

ELEMENTS : : Tet rahedron K;

initialisiert. Weiter seien die Koordinaten der vier Ecken sequentiell in einem Vektor der Lange zwolf

gespeichert. Zusatzlich werde eine zweidimensionale Datenstruktur mittels STL Vektoren fur die lokalen

Diskretisierungssterne initialisiert.

s t d : : v ec to r <double> c o o r d i n a t e s ( 1 2 ) ;

// x0 , y0 , z0 , x1 , y1 , z1 , x2 , y2 , z2 , x3 , y3 , z3

s t d : : v ec to r <s t d : : v ec to r <double> > s t e n c i l ;

Die Liste der Koordinaten des aktuellen Elements wird uber den Klammeroperator (operator()) an das

Finite Element K ubergeben, wodurch die Transformation und die damit zusammenhangenden Werte

berechnet werden konnen. Danach kann die Integration fur die schwache Formulierung des Laplace-

Operators aufgerufen werden:

s t e n c i l = K( c o o r d i n t e s ) . i n t e g r a t e ( grad ( v ( ) ) ∗ grad (w ( ) ) ) ;

Damit berechnet Colsamm fur alle 16 moglichen Kombinationen der vier linearen Basisfunktionen die

numerische Integration uber das Finite Element K mit den Eckpunkten PK0 , PK

1 , PK2 , PK

3 .

Die Werte dieses Diskretisierungssterns in der lokalen Nummerierung (0 bis 3) mussen an die ent-

sprechenden Positionen der globalen Matrix addiert werden. Dazu sind die Freiheitsgrade in der lokalen

Nummerierung mit den zugehorigen Freiheitsgraden in der globalen Nummerierung zu identifizieren.

Den Gesamtablauf der FEM-Diskretisierung stellt Listing 11.1 dar. Darin werden nochmals die ein-

zelnen Schritte zur Assemblierung der Diskretisierungsmatrizen mittels Colsamm aufgefuhrt, wobei

92

Page 109: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

FiniteElement elementList die Liste der Finiten Elemente beschreibt, die aus der Diskretisierung des Ge-

biets entstehen. Diese Objekte besitzen die Methode CoordinatesAndNumbering, welche die Koordinaten

des Elements und die globale Nummerierung der Freiheitsgrade auf diesem Element setzt.

Listing 11.1: Beispiel-Programm zur Anwendung von Colsamm

/∗ 1 . E r s t e l l u n g des D i s k r e t i s i e r u n g s g i t t e r s ∗/

F i n i t eE l emen t e l emen t L i s t ;

/∗ 2 . I n i t i a l i s i e r u n g de r g l o b a l e n D i s k r e t i s i e r u n g s m a t r i x ∗/

Spa r seMatr i x A ;

/∗ 3 . Anlegen des Te t r a ede r e l emen t s ∗/

ELEMENTS : : Tet rahedron K;

/∗ 4 . I n i t i a l i s i e r u n g de r H i l f s v e k t o r e n ∗/

s t d : : v ec to r <i n t > g l o b a l ( 4 ) ;

s t d : : v ec to r <double> c o o r d i n a t e s ( 1 2 ) ;

s t d : : v ec to r <s t d : : v ec to r <double> > s t e n c i l ;

/∗ 5 . I t e r a t i o n uebe r d i e Elemente ∗/

f o r ( i n t i =0; i < numberElements ; ++i )

/∗ 5 . 1 . Bestimmung der Koord ina ten und g l o b a l e n Nummerierung ∗/

e l emen t L i s t [ i ] . Coord inatesAndNumber ing ( coo r d i na t e s , g l o b a l ) ;

/∗ 5 . 2 . Se tz en de r Koord ina ten des a k t u e l l e n Elements ∗/

K( c o o r d i n a t e s ) ;

/∗ 5 . 3 . Berechnen der l o k a l e n D i s k r e t i s i e r u n g s m a t r i x ∗/

s t e n c i l = K. i n t e g r a t e ( grad ( v ( ) ) ∗ grad (w ( ) ) ) ;

/∗ 5 . 4 . Add i t i on zur g l o b a l e n D i s k r e t i s i e r u n g s m a t r i x ∗/

f o r ( i n t j =0; j < K. s i z e S e t 1 ( ) ; ++j )

f o r ( i n t k=0; k < K. s i z e S e t 1 ( ) ; ++k )

A[ g l o b a l [ j ] ] [ g l o b a l [ k ] ] += s t e n c i l [ j ] [ k ] ;

/∗ 6 . Loesung der numer i schen G l e i chungen ∗/

. . .

11.3 Integranden

Die Integranden der schwachen Formulierungen, die mittels Colsamm implementiert werden konnen,

bestehen aus den Kombinationen von Basisfunktionen mit Differentialoperatoren sowie problemspezifi-

schen Parametern und Funktionen. Diese konnen mit den naturlichen Rechenoperationen in sinnvoller

Art und Weise verknupft werden. Dafur verwendet Colsamm eine ET-Implementierung zur Speicherung

von Ausdrucken aus Kapitel 5.4. Diese Variante ermoglicht eine separate Deklaration und Kapselung

von Integrationstermen außerhalb des eigentlichen Integrationsaufrufs. Somit konnen auch komplexe

Integranden ubersichtlich programmiert werden, die sich sonst uber mehrere Zeilen erstrecken wurden.

Die Speicherung solcher Integrandenausdrucke in Variablen wird mittels des Makros Define Integrand (.)

durchgefuhrt (siehe auch Abschnitt 7.3). Dabei wird als erster Parameter die Integrandenformel gesetzt

und der Name des Ausdrucks als zweites. Damit kann beispielsweise der Gradient von zweidimensio-

nalen Basisfunktionen folgendermaßen gespeichert werden:

De f i n e I n t e g r a n d ( grad2D ( v ( ) ) , g rad v ) ;

Die so definierten Variablen sind wie gewohnt in den Integranden zu verwenden.

Neben der ET-Variante zur Abspeicherung der Integranden existiert auch eine FET-Implementie-

rung, die mit dem Compiler-Flag −DFET COLSAMM ausgewahlt werden kann. Dabei sind jedoch, wie

in Kapitel 6.2 beschrieben, alle ausdrucksabhangigen Werte in nummerierte Klassen zu speichern, was

die Anwendung weniger benutzerfreundlich macht. Andererseits kann dadurch bei manchen Compilern

eine performantere Berechnung der lokalen Steifigkeitsmatrizen erzielt werden. Im Folgenden werden

nun die moglichen Bestandteile der Integranden zusammengefasst, jedoch nur fur Anwendungen der

ersten ET-Variante.

93

Page 110: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.3. INTEGRANDEN

11.3.1 Platzhalter fur Basisfunktionen

Wie bereits im vorherigen Beispiel zu sehen, werden mit v () und w () die ϕi und ϕj aus der schwa-

chen Formulierung bezeichnet. Diese stehen fur Platzhalter der Funktionen aus der Menge der Ansatz-

und Testfunktionen. Intern werden dafur die jeweiligen vorberechneten Werte der Funktionen einge-

setzt und somit durch entsprechende Kombinationen mit der Transformation die Diskretisierungsster-

ne berechnet. Weiter kann eine zweite Menge von Basisfunktionen definiert werden, die in gemischten

FE-Ansatzen verwendet werden kann (Abschnitt 10.2.3). Dabei beschreibt p () einen Platzhalter fur

Funktionen aus dieser zweiten Menge der Basisfunktionen.

Aus dem Vorkommen dieser Platzhalter in den Integranden bestimmt sich die Dimension der re-

sultierenden Diskretisierungssterne. Die Große eines Sterns in den einzelnen Richtungen erfolgt nach

folgender Reihenfolge der Platzhalter: v → w → p. Der Anwender kann mit den Memberfunktionen

size Set1 () bzw. size Set2 () die jeweiligen Großen der lokalen Diskretisierungssterne abfragen.

Neben diesen Platzhaltern fur reellwertige Basisfunktionen existieren weitere Platzhalter fur zwei-

bzw. dreidimensionale Vektorbasisfunktionen. Diese lauten v vec2D(), w vec2D() bzw. v vec3D(), w vec3D(),

und besitzen eigene Berechnungsmethoden zur internen Bestimmung der Vektorfunktionen auf trans-

formierten Elementen aus den Basisfunktionen des Referenzelements.

11.3.2 Differentialoperatoren

Die in Colsamm implementierten Differentialoperatoren beschranken sich auf Operatoren erster Ord-

nung, welche fur die Realisierung einer Vielzahl von Problemen ausreichend sind. Neben dem Gradien-

ten grad (.) kann zur kann zur effizienteren Berechnung in 2D ein spezieller Operator grad2D(.) verwendet

werden. Des Weiteren sind die jeweiligen partiellen Ableitungen auch einzeln anwendbar: d dx (.) , d dy(.)

und d dz (.) . Fur vektorwertige Basisfunktionen sind die Rotationsoperatoren curl2D(.) und curl3D(.) de-

finiert.

In diese Operatoren konnen lediglich die vorher aufgefuhrten Platzhalter fur Basisfunktionen einge-

setzt werden. Da die zugrunde liegenden Ableitungen der Basisfunktionen durch die Anwendung der

Kettenregel mittels einer Matrix-Vektor-Multiplikation bereits intern vorberechnet werden, wurden

andere Terme in diesen Differentialoperatoren zu zusatzlichen Berechnungen und damit zu einem

Performance-Verlust fuhren. Doch auf Grund der Linearitat der Ableitung konnen Terme in den Dif-

ferentialoperatoren im Allgemeinen entsprechend umgeformt werden.

Zusatzlich zu diesen Differentialoperatoren erster Ordnung existieren fur die Randelemente noch

Funktionen zur Bestimmung der Normalenvektoren N () und der Einheitsnormalenvektoren N Unit().

11.3.3 Konstanten, Polynome, Vektoren

Die Differentialoperatoren konnen durch die ublichen Rechenoperationen mit beliebigen Konstanten

kombiniert werden, lediglich bei der Definition von Vektoren sind Konstanten mittels C (.) anzugeben.

Daruber hinaus konnen auch Polynome eingefuhrt werden (mittels x , y und z ), sowie die Exponential-

funktion (Exp(.)), die Quadratwurzel (Sqrt (.) ) oder die allgemeine Potenz (Pow(.,.)). Bei der Verwendung

von komplexwertigen Basisfunktionen, Ausdrucken oder Funktionen kann mittels der Funktion Conj(.)

das konjugiert Komplexe berechnet werden.

Zusatzlich konnen Vektoren definiert werden die aus Konstanten, Ausdrucken oder Funktionen be-

stehen und mit anderen Vektoren, Gradienten oder Vektorbasisfunktionen addiert, subtrahiert oder

multipliziert werden. Diese Vektoren werden durch Angabe der Komponenten, jeweils getrennt durch

den Operator &, implementiert. Beispielsweise wird der Vektor(

1, ∂v∂x , x

)

in Colsamm folgender-

maßen definiert:

( C (1) & d dx ( v ( ) ) & x <1>() )

94

Page 111: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

Daruber hinaus konnen Daten an den Freiheitsgraden des aktuellen Elements in den Integranden

eingefuhrt werden. Dafur sind die zugehorigen Daten in Arrays (in lokaler Nummerierung) abzuspei-

chern, und bei der Integration in Kombination mit den entsprechenden Basisfunktionen einzusetzen.

Enthalt z.B. das Feld data elementspezifische Werte an den Freiheitsgraden eines Elements, so kann

mittels

vec ( data ) ∗ v ( )

die Multiplikation der Basisfunktionen mit diesen Werten durchgefuhrt werden.

11.3.4 Benutzerdefinierte, veranderliche Funktionen

In Erganzung zu der in Abschnitt 11.3.3 erlauterten Methode Funktionen einzufuhren, wird die Ver-

wendung von benutzerdefinierten Funktionen angeboten. Die Funktion

double f u n c t i o n ( double x , double y , double z ) . . .

wird mittels func( function ) in Integranden eingefuhrt. Wird dabei eine Funktion verwendet, die eine

geringe Anzahl an Parametern besitzt als die Dimension des Referenzelements, so werden nur die x-

bzw. y-Koordinaten in der Funktion verwendet. Generell ist jedoch zu beachten, dass es sich bei dieser

Methode um die Einfuhrung von Call-Back-Funktionen handelt, die, wie bereits in Abschnitt 4.2.2

angesprochen, bei intensiver Nutzung einen Performanceverlust zur Folge haben. Aus diesem Grund

sollten Funktionen vorrangig mittels der Mechanismen aus Abschnitt 11.3.3 definiert werden.

11.4 Definition neuer Finiter Elemente

Zur Definition neuer Finiter Elemente werden Ableitungen der Klasse Domain eingefuhrt (siehe Anhang

B.2), wobei zur Vereinfachung sog. Zwischenelemente existieren (z.B. Simple Element, Vectorial Element).

Prinzipiell werden neben der entsprechenden Festlegung der Template-Parameter der Basisklasse auch

die Formeln der Basisfunktionen auf dem Referenzelement benotigt. Im Folgenden werden die zwei

wesentlichen Aspekte der Einfuhrung neuer Finiter Elemente genauer erlautert, die Definition der

Transformationsformeln und die Erstellung der Basisfunktionen.

11.4.1 Transformationen

Die Transformationen definieren die Abbildung der Referenzelemente auf beliebige Elemente mit ent-

sprechender Geometrie, wie bereits in Abschnitt 10.1.4 erlautert. Danach setzen sich die Formeln dieser

Transformationen aus den Kombinationen der Diskretisierungspunkten des Elements K multipliziert

mit den raumlichen Koordinatenfunktionen zusammen. Beispielsweise lautet die Abbildung fur Tetra-

eder mit den Eckpunkten (PK0 , PK

1 , PK2 , PK

3 )

TK(x, y, z) = PK0 + (PK

1 − PK0 )x + (PK

2 − PK0 )y + (PK

3 − PK0 )z.

Da die Berechnungen zu dieser Transformation fur jedes Element durchgefuhrt werden, basiert die zu-

grunde liegende Implementierung auf der leistungsfahigen FET-Technik (siehe Abschnitt 6.2). Dadurch

sind sehr effiziente Auswertungen der Transformationsabbildung moglich. Daruber hinaus werden in

den meisten Fallen keine ausdrucksabhangigen Konstanten benotigt, so dass die template-nummerierte

Einfuhrung von Werten im Allgemeinen nicht benotigt wird. Durch diese Art der Definition konnen die

Formeln als Typen gespeichert werden, und somit als Template-Parameter fur die Einfuhrung neuer

Elemente verwendet werden.

Zur Implementierung der obigen Transformationsformel in Colsamm werden die raumlichen Koor-

dinatenfunktionen x, y, und z durch U(), V() bzw. W() ersetzt. Die Speicherung der entstehenden

95

Page 112: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.4. DEFINITION NEUER FINITER ELEMENTE

FET-Ausdrucke wird mit dem Define Transformation-Makro durchgefuhrt. Dieses erhalt die Transfor-

mationsformel sowie den gewunschten Namen als Parameter (siehe Abschnitt 7.3). Damit sieht die

Implementierung der obigen Transformationsformel fur Tetraeder folgendermaßen aus:

Listing 11.2: Implementierung der Tetraeder-Transformationsformel.

De f i n e T r an s f o rma t i on (

P 0 ( ) + ( P 1 ( ) − P 0 ( ) ) ∗ U () +

( P 2 ( ) − P 0 ( ) ) ∗ V () +

( P 3 ( ) − P 0 ( ) ) ∗ W() ,

Te t r a hed r on Tran s f o rma t i on ) ;

Bei der Realisierung der Transformationen wurde besonders darauf geachtet, dass die jeweiligen For-

meln fur den Benutzer spezifisch definierbar sind. Je nach Problemstellung oder geometrischer Vorstel-

lung sind die Elemente im Diskretisierungsgitter unterschiedlich nummeriert. Die allgemeinen Defini-

tionen von Transformationsformeln in Colsamm erlauben es Anwendern, sehr intuitiv eigene Formeln

einzufuhren.

Auf die gleiche Weise konnen beispielsweise auch Transformationen fur isoparametrische Elemente

definiert werden, siehe Abbildung 10.3. Die Konstanten in den Transformationsformeln mussen aller-

dings mittels der Funktion C<.>(.) in FET-Typen gekapselt werden, wobei in den spitzen Klammern

eine eindeutige Nummerierung zu stehen hat. Damit kann die isoparametrische Transformation aus

Abschnitt 10.1.4

T K(x, y) = PK0 + (PK

1 − PK0 )x + (PK

3 − PK0 )y + (4PK

2 − 2(PK1 + PK

3 ))xy

wie folgt programmiert werden:

Listing 11.3: Transformationsformel fur FE-Dreiecke mit einer krummlinigen Seite.

De f i n e T r an s f o rma t i on (

P 0 ( ) + ( P 1 ( ) − P 0 ( ) ) ∗ U () +

( P 3 ( ) − P 0 ( ) )∗ V () +

( C<1>(4) ∗ P 2 ( ) − C<2>(2) ∗ ( P 1 ()+P 3 ( ) ) ) ∗ U ()∗ V ( ) ,

T r i a n g l e T r a n s f o r ma t i o n I s o ) ;

11.4.2 Basisfunktionen

Die Definition von Basisfunktionen findet entweder im Konstruktor der neu eingefuhrten Finiten Ele-

mente oder durch externe Methodenaufrufe statt. Dazu werden die verschiedenen Varianten der Funk-

tion Set (.) verwendet (genauer beschrieben in Abschnitt B.2). Da die Basisfunktionen intern abgespei-

chert werden, sind diese mittels der ET-Variante aus Listing 7.7 implementiert. Zur Definition der

Basisfunktionen konnen Terme aus Monomen (X , Y , Z ), Konstanten, Sinus-, Kosinus-, Exponential-

und Wurzelfunktionen, sowie komplexwertige Funktionen verwendet werden.

Listing 11.4: Definition eines Tetraederelements in Colsamm.

s t r u c t Tet r ahed r on : pub l i c Simple Element <4,D3 ,

Tet rahedron Trans f o rmat i on , 4 , Un i t Tet rahedron >

Tet r ahed r on ()

t h i s−>Set ( 1 . − X (1) − Y (1) − Z (1) ) ;

t h i s−>Set ( X (1) ) ;

t h i s−>Set ( Y (1) ) ;

t h i s−>Set ( Z (1) ) ;

;

Eine vollstandige Definition eines Tetraederelements mit linearen Basisfunktionen und der bereits

angefuhrten Transformationsformel ist in Listing 11.4 dargestellt. Darin legen die Template-Parameter

96

Page 113: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

bei der Ableitung von Simple Element gewisse Eigenschaften des Referenzelements fest. Entsprechend

der in Listing 11.4 auftretenden Reihenfolge der Template-Argumente sind dies: die Eckpunkte des

Elements (4), die Dimension (D3), die Transformationsformel (Tetrahedron Transformation), die Anzahl der

Basisfunktionen (4), sowie die Geometrie des Referenzelements (Unit Tetrahedron).

Um die flexible Nutzung von Colsamm zu demonstrieren, werden nachfolgend in der gleichen Weise

auch die Nedelec-Elemente aus Abschnitt 10.2.4 definiert. Dabei werden die vektorwertigen Basisfunk-

tionen mittels fVec (.) eingefuhrt. Zusatzlich ist fur jede Basisfunktion die Kante anzugeben, auf der sie

nicht-verschwindende Tangentialkomponenten besitzt (siehe auch Abbildung 10.4). Zusammen mit der

Transformation werden die sechs vektorwertigen Basisfunktionen

λ01 =

1 − y − z

x

x

, λ02 =

y

1 − x − z

y

, λ03 =

z

z

1 − x − y

,

λ12 =

y

−x

0

, λ13 =

z

0

−x

, λ23 =

0

z

−y

,

auf dem Referenztetraeder wie in Listing 11.5 implementiert.

Listing 11.5: Definition von Nedelec-Elementen erster Ordnung in Colsamm.

s t r u c t Vec to r Te t r a hed r on

: pub l i c Vec to r i a l E l emen t <4,D3 , Tet rahedron Trans f o rmat i on ,

6 , Un i t Tet rahedron >

Vec to r Te t r a hed r on ( )

t h i s−>Set ( fVec ( 1 − Y () − Z ( ) , X ( ) , X ( ) ) , 0 , 1 ) ;

t h i s−>Set ( fVec ( Y ( ) , 1 − X () − Z ( ) , Y ( ) ) , 0 , 2 ) ;

t h i s−>Set ( fVec ( Z ( ) , Z ( ) , 1 − X () − Y () ) , 0 , 3 ) ;

t h i s−>Set ( fVec ( Y ( ) , − X () , N u l l ( ) ) , 1 , 2 ) ;

t h i s−>Set ( fVec ( Z ( ) , N u l l ( ) , − X () ) , 1 , 3 ) ;

t h i s−>Set ( fVec ( Nu l l ( ) , Z ( ) , − Y () ) , 2 , 3 ) ;

;

11.5 Anwendungsbeispiele

Nach den Erlauterungen zur Benutzung von Colsamm werden im Folgenden einige praktische Anwen-

dungen der Template-Bibliothek betrachtet. Durch die einfachen und intuitiven Schnittstellen und den

klar definierten Funktionsumfang eignet sich Colsamm fur die Diskretisierung von partiellen Differen-

tialgleichungen in unterschiedlichsten Anwendungsgebieten.

Eine sinnvolle Rolle spielt Colsamm beispielsweise in der Lehre. So wird Studenten ein einfacher

Zugang zur Finiten Elemente Methode ermoglicht, ohne die zugrunde liegenden mathematischen Pro-

blemstellungen selbst implementieren zu mussen. Dadurch konnen bereits fruh komplexe Aufgabenstel-

lungen gelost werden, und somit das Verstandnis fur die FEM besser vertieft, sowie deren Moglichkeiten

leichter vermittelt werden.

Praxisrelevante Einsatzgebiete finden sich beispielsweise die Lasersimulation, wo Colsamm benutzt

wird, um die Ratengleichungen der Photonendichten in Halbleiterlasern zu diskretisieren. Eine wei-

tere Anwendung entstand in der Bibliothek ParExPDE [CBHR], die unter anderem zur numerischen

Simulation von Partikelbewegungen in Flussigkeiten verwendet wird. Zusatzlich dient Colsamm im Si-

mulationspaket des ORCAN-Software-Frameworks [THR05, Fra05] zur einfachen Diskretisierung von

passenden Problembeispielen. Nachfolgend werden zwei Anwendungen der Template-Bibliothek Col-

samm genauer beschrieben.

97

Page 114: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.5. ANWENDUNGSBEISPIELE

11.5.1 Finite Elemente im optischen Fluss

Der optische Fluss beschreibt die Bewegung von Bildpunkten in einer Folge von Bildern [Bru06]. Die

mathematische Problemstellung besteht dabei in der Berechnung eines approximierenden Bewegungs-

vektorfeldes u : Rd → Rd mit d ∈ 2, 3 aus zwei oder mehr aufeinander folgenden Bildern einer

d-dimensionalen Video-Sequenz,

I : Rd × T → R mit d, tmax ∈ N und T = [0, . . . , tmax].

Darin beschreibt I die Intensitat des Grauwerts fur jeden Punkt im Bildgebiet Ω und dem Zeitgebiet

T. Zusatzlich wird angenommen, dass sich die Grauwerte der bewegenden Bildobjekte nicht verandern,

d.h.

I(x, t) = I(x + u, t + 1) . (11.1)

gilt fur jeden Punkt (x, t) ∈ Rd×T. Diese Gleichung wird durch eine Taylor-Entwicklung und weglassen

der Terme hoherer Ordnung linearisiert. Damit erhalt man

uTt ∇tI ≈ 0 , (11.2)

wobei z.B. im zweidimensionalen ∇tI = (Ix, Iy, It) die Raum-Zeit-Ableitung und ut = (u, v, 1) das

Bewegungsfeld bezeichnet. Um den optischen Fluss ut zu berechnen, versucht man das Integral

D(∇tI,ut) =

Ω

(uTt ∇tI)2dx (11.3)

uber alle Punkte des Bildgebiets Ω zu minimieren. Dabei D wird Datenterm genannt.

Falls der Term (11.3) an einigen Stellen im Gebiet verschwindet, kann dort mit der Bedingung

(11.2) alleine der optische Fluss nicht berechnet werden. Um dennoch eine eindeutige Losung auf

dem gesamten Gebiet zu bekommen, muss das Problem regularisiert werden. Dies kann beispielsweise

durch diffusionsbasierte Modelle erreicht werden, bei denen angenommen wird, dass sich der optische

Fluss lokal nur sehr wenig verandert, d.h. der Gradient des Vektorfeldes klein bleibt. Beispiele von

Regularisierern sind:

• der homogene Diffusions-Regularisierer (HD) [HS81]

S1(u) =

Ω

d∑

i=1

|∇ui|2dx , (11.4)

welcher die Information homogen im gesamten Gebiet streut,

• ein isotroper Diffusions-Regularisierer (ID) [AELS99]

S2(u) =

Ω

g(

|∇I|2)

d∑

i=1

|∇ui|2dx , (11.5)

mit

g(s2) =1

1 + s2/ǫ2, ǫ > 0 (11.6)

welcher in der Nahe von Bildkanten die Diffusion reduziert, um das Bewegungsfeld an den Kanten

nicht zu verwischen, und

• ein anisotroper Diffusions-Regularisierer (AD) [Nag83]

S3(u) =

Ω

d∑

i=1

∇uTi T (∇I)∇uidx , (11.7)

98

Page 115: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

Abbildung 11.3: Frames 8 und 9 der bekannten Yosemite-Sequenz.

welcher den isotropischen Regularisierer erweitert, um das Glatten entlang der Kanten zu ermogli-

chen, jedoch nicht uber die Kante hinweg. Dabei ist

T (∇I) =1

‖∇I‖2 + 2ǫ2(∇I⊥∇I⊥T + ǫ2Id) , ǫ > 0 , (11.8)

wobei Id die Einheitsmatrix darstellt.

Der Datenterm kann mit den unterschiedlichen Regularisierern in einem Energiefunktional kombiniert

werden

Ei(u) :=

Ω

D(∇tI,ut) + αSi(u)dx , i ∈ 1, 2, 3, (11.9)

das es zu minimieren gilt. Eine notwendige Bedingung fur die Minimierung der Gleichung (11.9) stellt

die Losung der Euler-Lagrange-Gleichung

0 = ∇(uTt ∇tI) − α∇T (σi∇u) , i ∈ 1, 2, 3 (11.10)

dar, wobei σi die Diffusionstensoren beschreibt, welche fur die drei Regularisierer durch σ1 = Id,

σ2 = g(|∇I|2)Id und σ3 = T (∇I) definiert sind. Colsamm wird eingesetzt um die Euler-Lagrange-

Gleichungen zu diskretisieren.

Durch die Diskretisierung entsteht ein lineares System der Form

Ahuh = fh . (11.11)

Dabei beschreibt Ah ∈ MN×N(R) die System-Matrix, uh ∈ RN den zu bestimmenden Losungsvektor

und fh ∈ RN den Vektor der rechten Seite auf dem Gebiet Ωh. Zur schnellen Berechnung der Losung

werden Mehrgitterverfahren verwendet [TOS01, Bru06]. Die anschließende Visualisierung stellt die

Vektoren des Bewegungsfeldes in jedem Punkt dar.

Ublicherweise werden die Gleichungen mit der Finiten Differenzen Methode diskretisiert. Wird statt-

dessen Finite Elemente Methode eingesetzt, so entstehen großere Diskretisierungssterne, die mehr

Speicherbedarf und aufwandigere Algorithmen zur Folge haben. Andererseits resultieren aus diesen

FE-Approximationen aber stabilere Diskretisierungen.

Als zweidimensionales Beispiel wird in Abbildung 11.3 die bekannte Yosemite-Sequenz gezeigt. Dazu

prasentiert Abbildung 11.4 das Vektorfeld des optischen Flusses bzgl. beiden Yosemite-Bilder, resul-

tierend aus der FE-Diskretisierung uber Colsamm. Die linke Grafik zeigt das resultierende Vektorfeld

unter Verwendung des anisotropen Diffusions-Regularisierers, wahrend bei der rechten Grafik der ho-

mogene Diffusions-Regularisierer benutzt wurde. Dabei ist zu erkennen, dass der anisotrope Ansatz die

Bewegungen genauer erfasst als die homogene Regularisierung.

Als weiteres Anwendungsbeispiel zeigt Abbildung 11.5 verschiedene Geschwindigkeitsfelder einer 3D-

Sequenz von Herzbewegungen. Die Zeilen enthalten die transversal, sagittal und coronal Ansichten der

99

Page 116: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.5. ANWENDUNGSBEISPIELE

Abbildung 11.4: Optisches Flussfeld fur Frame 8 und 9 der Yosemite-Sequenz, visualisiert mittels LIC

(line integral convolution) [CL93, SK98, SK97] mit dem anisotropen Diffusions-Regularisierer (linke

Grafik) und dem homogenen Diffusions-Regularisierer (rechte Grafik).

Norm der Geschwindigkeitsfelder unter Verwendung aller drei erwahnten Regularisierer. Dabei stellt

sich der isotrope Diffusion-Regularisierer (mittlere Spalte) als qualitativ beste Variante heraus.

11.5.2 Quell-Lokalisation in Dipolmodellen

Ein zweites Anwendungsbeispiel der Template-Bibliothek Colsamm findet sich in den Quellenberech-

nungen der Dipolmodelle von Hirnstromen im Software-Paket NeuroFEM [Koo03], veroffentlicht in

[WKM+06b]. Im Allgemeinen wird in der Elektroenzephalografie (EEG) zur inversen Bestimmung der

Primarstromquellen ein mathematisches Dipolmodell herangezogen, um die zugrunde liegende Strom-

verteilung im Gehirn zu beschreiben. Diese inversen Methoden basieren auf der Losung des zugehorigen

Vorwartsproblems, welches die Simulation des elektrischen Potenzials des Kopfes als Volumenleiter fur

einen Dipol in der Cortex-Schicht des menschlichen Gehirns beinhaltet.

Die zugrunde liegenden Stromungen im Gehirn werden durch die Maxwell-Gleichungen beschrieben

[PH67]. Es bezeichnen E und D das elektrische Feld sowie die elektrische Flussdichte, ρ die elektri-

sche Ladungsdichte, ǫ die elektrische Leitfahigkeit und j die elektrische Stromdichte. Des Weiteren

beschreibt µ die magnetische Leitfahigkeit und H bzw. B bezeichnen die magnetische Feldstarke bzw.

die magnetische Flussdichte. In der entsprechenden niedrigen Frequenz (kleiner als 2 MHz) konnen der

Gewebewiderstand, der induktive Effekt und der elektromagnetische Ausbreitungseffekt vernachlassigt

werden. Weiter kann angenommen werden, dass µ auf dem gesamten Gebiet konstant ist und gleich

der magnetischen Leitfahigkeit im Vakuum [PH67]. Mit diesen Bezeichnungen und Annahmen lassen

sich die quasi-statischen Maxwell-Gleichungen wie folgt schreiben

∇ · D = ρ

∇× E = 0

∇× H = µj (11.12)

∇ · B = 0. (11.13)

mit den Material-Gleichungen (da sich biologisches Gewebe wie ein Elektrolyt verhalt)

D = ǫE

B = µH.

Das elektrische Feld kann als negativer Gradient eines skalaren Potenzials dargestellt werden,

E = −∇Φ. (11.14)

100

Page 117: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

(a) Trans. Schnitt 126 (HD). (b) Trans. Schnitt 126 (ID). (c) Trans. Schnitt 126 (AD).

(d) Sag. Schnitt 111 (HD). (e) Sag. Schnitt 111 (ID). (f) Sag. Schnitt 111 (AD).

(g) Cor. Schnitt 112 (HD). (h) Cor. Schnitt 112 (ID). (i) Cor. Schnitt 112 (AD).

Abbildung 11.5: Visualisierung der Norm des berechneten Geschwindigkeitsfeld einer Sequenz von

Herzbewegungen bzgl. transversalen (erste Zeile), sagittalen (zweite Zeile), und coronalen (dritte Zeile)

Ansichten. Verwendet wurden der homogene Diffusions-Regularisierer (HD), der isotrope Diffusions-

Regularisierer (ID) und der anisotrope Diffusions-Regularisierer (AD).

Weiter spaltet sich im Bioelektromagnetismus die elektrische Stromdichte in zwei Teile auf, die sog.

primare und die sekundare Stromdichte, bezeichnet mit jp bzw. σE,

j = jp + σE, (11.15)

wobei σ einen 3 × 3 Leitfahigkeitstensor darstellt.

Bei der Beschreibung des Vorwartsproblems entsteht durch Divergenzbildung in Gleichung (11.12)

und unter Verwendung der Gleichungen (11.14) und (11.15) die Poisson-Gleichung

∇ ·(

σ∇Φ)

= ∇ · jp = Jp in Ω. (11.16)

Diese beschreibt die Verteilung des Potenzials im (Kopf-)Gebiet Ω bzgl. einer primaren Stromdichte jp

101

Page 118: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.5. ANWENDUNGSBEISPIELE

in der Cortex-Schicht des menschlichen Gehirns. Die zugehorigen Randbedingungen auf der Oberflache

Γ lauten(

σ1∇Φ1,n)∣

Γ=

(

σ2∇Φ2,n)∣

Γ

wobei n die Einheitsnormale der Oberflache beschreibt, welche die Stetigkeit der Stromdichte bzgl.

der Oberflachenregionen mit verschiedenen Leitfahigkeiten ausdruckt. Fur die Kopfoberflache Γ = ∂Ω

ergeben sich homogene Neumann-Randbedingungen,

(

σ∇Φ,n)∣

Γ= 0. (11.17)

Zusatzlich benotigt man noch eine Referenz-Elektrode mit einem vorgegebenen Potenzial, d.h.

Φref = 0 . (11.18)

Die primaren Stromdichten beschreiben die Ionenbewegungen innerhalb der Dendriten von großen

pyramidrischen Zellen der aktivierten Regionen in der Cortex-Schicht. Bei der Neuronengenerierung

mittels evozierter Felder ist bereits in kleinen Abstanden zur aktivierten Region ausschließlich das

Dipolmoment der Quelle sichtbar [WKM+06b]. Dieser sog. mathematische Dipol jp := Mδ(x − x0) an

der Stelle x0 ∈ R3 mit dem Moment M ∈ R3 kann geschrieben werden als

Jp(x) = ∇ · jp (x) := ∇ · Mδ(x− x0) . (11.19)

Zur Formulierung des Subtraktions-Ansatzes [WKM+06b] wird angenommen, dass ein nicht-leeres

Teilgebiet Ω∞ ⊂ Ω um die Quelle x0 mit homogener konstanter Leitfahigkeit σ∞ existiert, so dass

x0 ∈ Ω∞ / ∂Ω∞ gilt. Bei der Substraktionsmethode wird die Leitfahigkeit σ in zwei Teile gespaltet

σ = σ∞ + σcorr, (11.20)

so dass σ∞ im gesamten Gebiet Ω konstant ist und fur σcorr in einem kleinen Teilgebiet Ω∞ σcorr(x) =

0, ∀x ∈ Ω∞ gilt. Ebenso wird auf diesen Gebieten das Gesamtpotenzial aufgespalten:

Φ = Φ∞ + Φcorr. (11.21)

Dabei stellt das Singularitatspotenzial Φ∞ die Losung eines Dipols in einem unbeschrankten homogenen

Leiter mit konstanter Leitfahigkeit σ∞ dar. Im Falle einer anisotropen Leitfahigkeit in Ω∞ wird das

Singularitatspotenzial beschrieben durch die Funktion [MS99]

Φ∞(x) =1

4π√

detσ∞

〈 ~M, (σ∞)−1(~x − ~x0)〉(〈(σ∞)−1(~x − ~x0), (~x − ~x0)〉)3/2

. (11.22)

Subtrahiert man die Poisson-Gleichung ∆Φ∞ = Jp · (σ∞)−1 von der Gleichung (11.16), erhalt man

eine Poisson-Gleichung fur das Korrektur-Potenzial:

−∇ ·(

σ∇Φcorr)

= f in Ω, f = ∇ ·(

σcorr∇Φ∞)

mit inhomogenen Neumann-Randbedingungen auf der Oberflache

σ∂Φcorr

∂n= g auf Γ, g = −σ

∂Φ∞

∂n.

Zur numerischen Berechnung von Φcorr kann das skalare Potenzial Φ uber die Gleichung (11.21) be-

stimmt werden. Durch diesen Subtraktions-Ansatz wird die Singularitat der rechten Seite von Gleichung

(11.23) eliminiert, da in Ω∞ das Korrektur-Potenzial σcorr verschwindet. Damit ist die gesamte rechte

Seite auf Ω∞ gleich Null.

102

Page 119: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

Zur numerischen Simulation von realistischen Kopfmodellen wird die Finite Elemente Methode ver-

wendet, da dadurch beliebige Geometrien sowie die anisotropen Materialeigenschaften direkt erfasst

werden konnen. Dazu wird zunachst die rechte Seite mittels partieller Integration umgeformt:

〈l, v〉 =

Ω

fvdΩ +

Γ

gvdΓ = −∫

Ω

∇v σcorr∇Φ∞dΩ −∫

Γ

〈σ∞∇Φ∞,n〉v dΓ (11.23)

Damit erhalt man die Formulierung∫

Ω

〈σ∇u,∇v〉dΩ = −∫

Ω

∇v σcorr∇Φ∞dΩ −∫

Γ

〈σ∞∇Φ∞,n〉v dΓ . (11.24)

Die Assemblierung der resultierenden Diskretisierungsmatrizen basiert auf Colsamm, wobei in der

aktuellen Realisierung lediglich die Randintegrale mittels der Template-Bibliothek berechnet werden.

Abbildung 11.6: Links: Schnitt durch das Tetraeder-Finite-Elemente Kopf-Modell mit EEG- (Elek-

troenzephalografie) Elektroden. Dabei sind die Oberflachen der inneren und außeren Schadeldecke

angedeutet. Rechts: Verteilung des elektronischen Potenzials einer quasi-radialen Dipolquelle in der

primaren Cortex-Schicht. Berechnet wurde diese Dipolquelle mittels eines Drei-Schichten-Ansatzes

(Haut, Schadel, Gehirn) eines realistischen Kopfmodells, diskretisiert durch Hexaedergitter.

11.6 Entwicklung und Zusammenfassung

Die Template-Bibliothek Colsamm dient als Beitrag zur einfachen Realisierung von FE-Diskretisie-

rungen. Durch den grundsatzlichen Anspruch, keine Einschrankungen an die zugrunde liegenden Dis-

kretisierungsgitter zu stellen, ergaben sich Einsatzmoglichkeiten in den verschiedensten Gebieten des

wissenschaftlichen Rechnens. Durch die intuitive Implementierung der schwachen Formulierungen der

partiellen Differentialgleichungen kann die FEM spezifisch fur die jeweilige Problemstellung angewandt

werden. Somit eignet sich Colsamm nicht nur fur anwendungsorientierte Entwickler, sondern auch fur

die Untersuchung passender Diskretisierungen mit benutzerdefinierten Finiten Elementen. Daruber

hinaus ermoglicht das Programm in der Ausbildung einen einfachen Einstieg in die FEM.

11.6.1 Schnelle Berechnungen der lokalen Steifigkeitsmatrizen

Durch den grundlegenden Aufbau als Template-Bibliothek liefert Colsamm sehr effiziente Programme

und kann somit auch in Hoch- oder Hochstleistungsrechnen eingesetzt werden. Beispielsweise ermoglicht

103

Page 120: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.6. ENTWICKLUNG UND ZUSAMMENFASSUNG

die elementbezogene Berechnung der lokalen Steifigkeitsmatrizen eine naturliche Parallelisierung der

Assemblierung der gesamten Diskretisierung.

Durch die ausgewogene Wahl der Diskretisierungseigenschaften, die in Template-Parameter gekapselt

sind, entstand eine leistungsstarke und dennoch flexible Bibliothek. Dadurch konnen Entscheidungen

zur Laufzeit vermieden werden, da bereits wahrend des Compilierens die entsprechende Programmie-

rung instantiiert wird. Dies ermoglicht daruber hinaus entscheidende Optimierungen wie etwa Inlining.

Trotz der als Templates gekapselten Eigenschaften konnen die Finite Elemente durch die Template-

Vererbung sehr intuitiv implementiert und verwendet werden. Dazu dienen vor allem die in den Kapi-

teln 5, 6 und 7 entwickelten ET-Techniken, um effiziente Realisierungen der uberladenen Operatoren

zu erhalten. Diese finden in der Implementierung der Transformationsformeln sowie bei der Defini-

tion der Basisfunktionen Anwendung. Auch die Programmierung der schwachen Formulierungen im

Anwendercode wird durch leistungsstarke ET-Implementierungen unterstutzt.

Neben diesen programmiertechnischen Grundlagen basiert die Leistungsfahigkeit von Colsamm vor

allem auf dem wohlstrukturierten Programmaufbau. Die Aufteilung der lokalen FE-Diskretisierung in

drei Stufen verhindert unnotige Berechnungen bereits aktualisierter Werte. Dabei werden bei der In-

itialisierung der Elemente alle Auswertungen bzgl. des Referenzelements durchgefuhrt und gespeichert.

In ahnlicher Weise werden nach dem Setzen der Diskretisierungspunkte die transformationsspezifischen

Werte berechnet und intern gesichert. Zuletzt werden bei der Integration die gespeicherten Werte ent-

sprechend der schwachen Formulierung die lokalen Diskretisierungssterne zusammengestellt. So konnen

beispielsweise mehrere Steifigkeitsmatrizen auf einem Element berechnet werden, ohne jedesmal die zu-

gehorigen Werte der Transformation bestimmen zu mussen.

Generell bietet somit Colsamm die Voraussetzungen, um effiziente Assemblierungen der lokalen

Diskretisierungsmatrizen durchzufuhren. Dabei ist naturlich zu berucksichtigen, dass in strukturier-

ten Gittern und translationsunabhangigen Integranden die Diskretisierungssterne durch entsprechende

Skalierung schneller berechnet werden konnen. In den allgemeinen Fallen werden jedoch die gleichen

Berechnungsschritte wie in Colsamm benotigt.

11.6.2 Erweiterungen und Ausblick

In der aktuellen Realisierung konnen mittels Colsamm Differentialoperatoren erster Ordnung diskre-

tisiert werden. Dadurch wird bereits eine große Anzahl der praxisrelevanten Problemstellungen abge-

deckt. Daruber hinaus treten beispielsweise in der schwachen Formulierung der biharmonischen Glei-

chung [GR05]∫

Ω

∆u∆v dµ =

Ω

fv dµ

Differentialoperatoren zweiter Ordnung auf. Diese konnen prinzipiell mit den bereits in Colsamm rea-

lisierten Mechanismen behandelt werden, zusatzlich sind jedoch die zweiten Ableitungen der Basis-

funktionen und der Transformation zu berechnen. Die Bestimmungen und Auswertungen der zweiten

Ableitungen der Basisfunktionen ergeben keinen Performance-Nachteil. Da jedoch die Berechnung der

Transformationswerte unabhangig vom ubergebenen Integranden geschieht, wurde die Hessematrix

der Transformation berechnet, selbst wenn diese nicht benotigt wird. Dies wurde die Leistungsfahig-

keit entscheidend beeintrachtigen. Um dies zu umgehen musste der Benutzer bereits beim Setzen der

Diskretisierungspunkte festlegen, ob die zweiten Ableitungen benotigt werden. Dies wurde jedoch auch

die Grenzen der einzelnen Berechnungsschritte verwischen.

Zusatzliche Erweiterungen von Colsamm sind fur die Realisierung von C1- bzw. C2-Elementen denk-

bar. In den zugehorigen Finiten Elementen existieren dadurch Basisfunktionen, die als Freiheitsgrad

nur einen Gradient in einer bestimmten Richtung besitzen. Wahrend diese Ansatze fur strukturier-

te Gitter einfach durchfuhrbar sind, mussen bei gedrehten Elementen die entsprechenden Richtungen

uber Multiplikation mit der Jacobi-Matrix miteinander kombiniert werden, siehe Abschnitt 10.1.4. Da-

zu sind die zusammengehorigen Basisfunktionen bei der Initialisierung im Element zu kennzeichnen.

104

Page 121: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 11. COLSAMM

Außerdem wird bei nicht-affinlinearen Abbildungen wie vorher die Hesse-Matrix der Transformation

benotigt, um die vollstandige Berechnung der Kettenregel durchfuhren zu konnen.

Trotz dieser moglichen Erweiterungen stellt Colsamm bereits jetzt eine sehr vielfaltig einsetzbare

Bibliothek dar, mittels der viele der bestehenden Finiten Elemente Diskretisierungen durchgefuhrt

werden konnen. Dies soll vor allem auch Anwender aus Anwendungsgebieten darin unterstutzen, die

Finite Elemente Methode zur approximativen Losung der eigenen PDG einsetzen zu konnen, ohne sich

mit den mathematischen Details befassen zu mussen.

105

Page 122: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

11.6. ENTWICKLUNG UND ZUSAMMENFASSUNG

106

Page 123: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 12. WEITERE EINSATZGEBIETE VON ET

12 Weitere Einsatzgebiete von ET

Nach den Erlauterungen zur Template-Bibliothek Colsamm, die einen Großteil der in Teil II entwickel-

ten Techniken verwendet, werden in diesem Kapitel weitere Einsatzmoglichkeiten von ET zum Losen

partieller Differentialgleichungen prasentiert. Zunachst wird eine einfache Anwendung diskutiert, die

jedoch demonstriert, wie unterschiedliche ET-Implementierungen kombiniert werden.

12.1 Mengenalgebren mittels ET

Die Grundgebiete der Differentialgleichungen werden im Allgemeinen uber Funktionen, welche die

Rander beschreiben, modelliert. Damit kann entschieden werden, ob ein Punkt innerhalb oder außer-

halb des Gebietes liegt. Diese Beschreibung der Gebiets und der Rander wird zur Generierung des

Diskretisierungsgitters und zur Initialisierung der Variablen mit den Randwerten benotigt. Daneben

werden beispielsweise zur Erstellung adaptiver Gitter Konstuktionen von Teilgebieten benotigt. Eine

leistungsstarke und einfach anwendbare Bibliothek zur Definition und Verknupfung solcher Mengen

kann mittels ET realisiert werden. Dies wurde zum Teil bereits in der Bibliothek ExPDE [Pfl01] ein-

gesetzt, doch wird nachfolgend ein allgemeinerer Ansatz diskutiert.

Eine entsprechende Realisierung besteht aus zwei verknupften ET-Implementierungen. Zunachst

werden Mechanismen zum Beschreiben von Funktionen eingefuhrt, mittels derer Polynome, trigono-

metrische Funktionen, etc. gebildet werden konnen. Da diese Funktionen zur Definition von Gebieten

eingesetzt werden sollen, die auch abspeicherbar und wieder verwendbar sind, wird dazu eine ET-

Implementierung mit vollen Objekten (Abschnitt 5.4) benutzt. Die Zeilen 1 bis 20 in Listing 12.1

zeigen Teile der zugehorigen Programmierung, unter anderem fur die Monome und die Addition. Die

weiteren Funktionenklassen werden auf die gleiche Weise implementiert. Der Auswertungsoperator

operator() berechnet aus den Daten des ubergebenen Feldes das Resultat der jeweiligen Funktion.

Zusatzlich zu diesen Funktionen werden die Testvorschriften, die bestimmen ob ein Punkt innerhalb

des Gebiets liegt, ebenfalls mittels ET-Konstrukten implementiert. Dazu wird eine eigene Wrapper-

Klasse (Bool Expr) eingefuhrt, welche die ET-Ausdrucke kennzeichnet, die einen booleschen Wert er-

geben. Davon abgeleitet werden dann Operationsklassen fur die zugehorigen Vergleichsoperationen

definiert. Listing 12.1 enthalt in den Zeilen 23 bis 31 den Programmcode zum “Kleiner“-Operator

(operator<). Die anderen Vergleichsoperatoren werden analog realisiert. Des Weiteren sollen bestehen-

de Gebietsdefinitionen logisch verknupft werden konnen, um daraus neue Gebiete zu erhalten. Dafur

sind vor allem die Standard-Mengen-Operationen, wie Schnitt, Vereinigung oder Komplementbildung

wichtig. Da das Resultat dieser Operationen wieder Ausdrucke sind, die fur jeden Punkt einen boo-

leschen Wert ergeben, werden diese Operationen auch von Bool Expr abgeleitet. Die Programmierung

der Schnittmenge zweier Gebiete wird in den Zeilen 34 bis 43 von Listing 12.1 gezeigt. Als Operator

fur das Bilden der Schnittmenge wird dabei das logische Und verwendet, weil ein Punkt im Schnitt in

beiden Mengen liegen muss.

Die Benutzung dieser ET-Bibliothek im Anwendercode erfolgt durch die uberladenen Operatoren

wieder ganz intuitiv. Durch ein zusatzlich definiertes Makro Define Domain, das die ET-Objekte in Va-

riablen abspeichert (Abschnitt 7.3), konnen Gebietsdefinitionen gekapselt werden. Bei der Verwendung

sollte jedoch beachtet werden, dass beispielsweise bei Iterationen uber Gitterpunkte die ET-Objekte

nicht in jedem Iterationsschritt neu gebildet werden (Zeilen 4 bis 6 in Listing 12.2). Durch eine wieder-

holte Generierung der zugehorigen ET-Ausdrucke kann sich die Effizienz verschlechtern. Stattdessen

107

Page 124: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

12.1. MENGENALGEBREN MITTELS ET

sollte ein Gebiet vor der Schleife in eine neue Variable gespeichert werden (Listing 12.2). Damit wird

die gewunschte Performance erreicht.

Listing 12.1: ET-Implementierung der Test- und Verknupfungsklassen zur Realisierung einer Men-

genalgebra.

template <c l a s s E> s t r u c t Expr ;

template < i n t pos>

c l a s s Monom : pub l i c Expr<Monom <pos> >

i n t exponent ;

5 pub l i c :

Monom ( i n t expo ) : exponent ( expo )

double ope ra to r ( ) ( double∗ data ) const r e t u r n s t d : : pow( data [ pos ] , exponent ) ;

;

i n l i n e Monom <0> x ( i n t expo ) r e t u r n Monom <0>(expo ) ;

10 i n l i n e Monom <1> y ( i n t expo ) r e t u r n Monom <1>(expo ) ;

i n l i n e Monom <2> z ( i n t expo ) r e t u r n Monom <2>(expo ) ;

template <c l a s s L , c l a s s R>

c l a s s Add : pub l i c Expr<Add<L ,R> >

const L l ; const R r ;

15 pub l i c :

Add ( const L& l , const R& r ) : l ( l ) , r ( r )

double ope ra to r ( ) ( double ∗ data ) const r e t u r n l ( data ) + r ( data ) ;

;

template<c l a s s L , c l a s s R>

20 i n l i n e Add<L ,R> ope ra to r + ( const Expr<L>& l , const Expr<R>& r ) ;

template <c l a s s E> s t r u c t Boo l Expr ;

template<c l a s s L , c l a s s R>

c l a s s Less Than : pub l i c Bool Expr<Less Than<L ,R> >

const L l ; const R r ;

25 pub l i c :

Less Than ( const L& l , const R& r ) : l ( l ) , r ( r )

boo l ope ra to r ( ) ( double ∗ data ) const r e t u r n l ( data ) < r ( data ) ;

;

template<c l a s s L , c l a s s R>

30 i n l i n e Less Than<L ,R> ope ra to r < ( const Expr<L>& l , const Expr<R>& r ) ;

template <c l a s s L , c l a s s R>

c l a s s I n t e r s e c t i o n : pub l i c Bool Expr<I n t e r s e c t i o n <L ,R> >

const L l ; const R r ;

pub l i c :

35 I n t e r s e c t i o n ( const L& l , const R& r ) : l ( l ) , r ( r )

boo l ope ra to r ( ) ( double ∗ data ) const r e t u r n l ( data ) & r ( data ) ;

;

template <c l a s s L , c l a s s R>

i n l i n e I n t e r s e c t i o n <L ,R> ope ra to r & ( const Bool Expr<L>& l , const Bool Expr<R>& r ) ;

Der Vorteil dieser ET-Implementierung im Vergleich zu Call-Back-Funktionen besteht in der besseren

Lesbarkeit und Wartbarkeit des Anwendercodes. Die Definitionen der Gebiete befinden sich direkt an

der Stelle des Programms, an der sie verwendet werden. Vergleichbare Implementierungen mit Funktio-

nen haben ihre Definition an anderer Stelle im Programm, oft sogar in anderen Dateien. Daneben sind

fur diese ET-Konstrukte eigene Ausgabe-Operatoren definierbar, die nutzliche Informationen wahrend

des Programmlaufs ausgeben, um so die Fehlersuche zu erleichtern.

Listing 12.2: Verwendung der ET-Mengenalgebra im Anwendercode.

Def ine Domain ( x (1)+y (1) < z (1 ) , domain 1 ) ;

Def ine Domain ( z (2) < 19 , domain 2 ) ;

// Auswertung , G e b i e t s e r s t e l l u n g i n de r S c h l e i f e

f o r ( i n t i = 0 ; i < s i z e ; ++i ) ( domain 1 & ! domain 2 ) [ data ] ;

// Auswertung , G e b i e t s e r s t e l l u n g vor de r S c h l e i f e

Def ine Domain ( domain 1 & ! domain 2 , domain 3 ) ;

f o r ( i n t i = 0 ; i < s i z e ; ++i ) domain 3 [ data ] ;

108

Page 125: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 12. WEITERE EINSATZGEBIETE VON ET

Nach dieser Anwendung von ET-Implementierungen zur Konstruktion von Gebieten, werden im

Folgenden ET eingesetzt, um Iterationsschleifen zu kapseln.

12.2 Iterationsschleifen mittels ET

Die bisher aufgefuhrten ET-Anwendungen waren darauf ausgelegt, vorwiegend mathematische Aus-

drucke zu kapseln, indem mittels der uberladenen Operatoren die zugehorigen Ausdrucksbaume auf-

gebaut wurden. In diesem Abschnitt wird das ET-Konzept dazu verwendet, Iterationsschleifen in ent-

sprechende ET-Objekte umzuwandeln, und diese anschließend auszuwerten. Eine nutzliche Anwendung

findet sich im darauf folgenden Abschnitt 12.3, in dem ein intuitiv anwendbares Schleifenblocking rea-

lisiert wird.

Schleifenubergreifende Optimierungen von ET-Ausdrucken sind bei der Benutzung von C++-Com-

pilern, die direkt Assemblercode erzeugen, kaum oder gar nicht durchfuhrbar. Betrachtet man bei-

spielsweise eine ET-Implementierung fur Vektoren, so ist dabei jede außere Schleife von der Iterati-

onsschleife in der Auswertungsmethode der Vektorklasse getrennt. Somit konnen weder vom Compiler

noch vom Programmierer Schleifenoptimierungen durchgefuhrt werden. Als einfaches Beispiel hierfur

betrachten wir die mittels Finite Differenzen diskretisierte zweidimensionale Poisson-Gleichung auf

dem Einheitsquadrat. Der daraus resultierende Gauß-Seidel-Loser kann mittels entsprechender ET-

Implementierungen folgendermaßen geschrieben werden (N, S, W, E bezeichnen die Richtungen im Dis-

kretisierungsgitter, h die Gitterweite, b die rechte Seite und u den Losungsvektor):

f o r ( i n t i =0; i < i t e r max ; ++i )

u = 0.25 ∗ ( 1 . / ( h∗h ) ∗ b + N(u ) + S(u ) + W(u ) + E(u ) ) ;

Um schleifenubergreifende Operationen zu ermoglichen, muss die Auswertung des Ausdrucks – genau

wie beim herkommlichen ET-Ansatz – ein weiteres Mal verzogert werden. Dafur werden im Folgenden

die ET-Implementierungen zur Beschreibung von Iterationsschleifen prasentiert.

Fur die verzogerte Auswertung definiert die Klasse Evaluate in Listing 12.3 eine Datenstruktur zum

Speichern des Ergebnisvektors

Listing 12.3: Datenstruktur fur die verzogerte Auswertung in Iterationsschleifen.

template <c l a s s R, c l a s s E>

c l a s s Eva l ua t e

R& r e s u l t ; const E& expr ;

pub l i c :

E v a l ua t e (R& re s , const E& e ) : r e s u l t ( r e s ) , expr ( e )

vo id i t e r a t i o n ( ) const r e s u l t = expr ;

;

und des Ausdrucks. Da dem Ergebnisvektor beim Aufruf der Methode iteration das Ergebnis zugewiesen

wird, kann diese Membervariable (R& result) nicht als konstante Referenz deklariert werden.

Um die bisherige Funktionalitat des Zusweisungsoperators der Klasse Vector zu erhalten, wird mit

dem Operator operator== eine weitere Zuweisung definiert. Diese erzeugt aus einem ET-Ausdruck ein

Evaluate-Objekt.

Listing 12.4: Zusweisungsoperator zur Durchfuhrung der verzogerten Auswertung.

c l a s s Vector . . .

template<c l a s s E>

Eva lua te<Vector , E> ope ra to r==(const Expr<E>& expr )

r e t u r n Eva lua te<Vector , E>(∗ t h i s , exp r ) ;

;

109

Page 126: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

12.2. ITERATIONSSCHLEIFEN MITTELS ET

Nach diesem Mechanismus zum Verzogern der Auswertung von Vektorausdrucken, werden Implemen-

tierungen fur die Darstellung von Iterationsschleifen mittels ET-Objekten diskutiert. Die Zielsetzung

besteht in einer Konstruktion, die den for-Schleifen in C++ sehr ahnlich ist.

Fur die Realisierung von Iterationsschleifen wird ein Laufindex benotigt. Dazu wird zunachst ein

Wrapper IndexEpr eingefuhrt, der Ausdrucke von Indizes enthalten kann. Die mittes IndexEpr gekapselten

Ausdrucke besitzen alle eine Methode iter , die den aktuellen Indexwert zuruckgibt. Eine passende

Implementierung einer Index-Klasse findet sich in Listing 12.9.

Listing 12.5: Wrapper-Klasse fur Index-Ausdrucke

template <c l a s s E>

s t r u c t I ndexEpr

ope ra to r const E& () const r e t u r n ∗ s t a t i c c a s t <const E∗>( t h i s ) ;

ope ra to r E& () r e t u r n ∗ s t a t i c c a s t <E∗>( t h i s ) ;

;

Eine Schleifendefinition besteht – ganz allgemein betrachtet – aus drei Teilen, einer Initialisierung,

einer Bedingung und einem Ausdruck. Zunachst wird die ET-Implementierung zur Schleifeninitialisie-

rung erlautert (Listing 12.6). Darin werden um den Wrapper LoopInit Initialisierungsklassen definiert,

die einen Index mit einem gespeicherten Wert bzw. Index-Ausdruck initialisieren.

Listing 12.6: ET-Programmierung der Schleifeninitialisierung.

template <c l a s s A>

s t r u c t Loop I n i t ope ra to r const A& () const ; ;

template <c l a s s A, c l a s s B>

c l a s s I n i t C : pub l i c Loop In i t <I n i tC <A,B> >

A& a ; const B b ;

pub l i c :

I n i t C (A& a , const B& b ) : a ( a ) , b ( b )

vo id i n i t ( ) const a . i t e r ( ) = b ;

;

template <c l a s s A, c l a s s B>

c l a s s I n i t I : pub l i c Loop In i t < I n i t I <A,B> > . . .

vo id i n i t ( ) const a . i t e r ( ) = b . i t e r ( ) ;

;

Dabei ist der Index (Membervariable A& a) nicht als konstant deklariert, da dieser ja im Laufe der In-

itialisierung verandert wird. Die zugehorigen Operatoren zum Erstellen der Initialisierungsobjekte sind

in der Klasse Index implementiert (Listing 12.9). Die in den Initalisierungsklassen definierte Methode

init , fuhrt die jeweilige Initialisierung durch.

Listing 12.7: ET-Code zur Durchfuhrung von Bedingungsabfragen.

template <c l a s s A>

s t r u c t LoopCond i t i on ope ra to r const A& () const ; ;

template <c l a s s A, c l a s s B>

c l a s s LessThanC : pub l i c LoopCondi t ion <LessThanC<A,B> >

const A& a ; B b ;

pub l i c :

LessThanC ( const A& a , const B& b ) : a ( a ) , b ( b )

boo l i sT rue ( ) const r e t u r n a . i t e r ( ) < b ;

;

template <c l a s s A, c l a s s B>

c l a s s LessThanI : pub l i c LoopCondi t ion <LessThanI<A,B> > . . .

boo l i sT rue ( ) const r e t u r n a . i t e r ( ) < b . i t e r ( ) ;

;

template <c l a s s A>

i n l i n e LessThanC<A, i n t > ope ra to r < ( const IndexEpr<A>& a , i n t i ) ;

template <c l a s s A, c l a s s B>

i n l i n e LessThanI<A,B> ope ra to r < ( const IndexEpr<A>& a , IndexEpr<B>& b ) ;

110

Page 127: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 12. WEITERE EINSATZGEBIETE VON ET

Die Kapselung der Bedingungsabfragen durch ET-Konstrukte wird ahnlich implementiert (Listing

12.7). Hierbei werden uber die Wrapper-Klasse LoopCondition entsprechende Vergleichsklassen eingefuhrt.

Diese testen in der Methode isTrue den in der Testklasse gespeicherten Ausdruck mit einer Konstanten

bzw. einem Index-Ausdruck.

Zuletzt benotigt man eine ET-Implementierung zur Erhohung bzw. Erniedrigung der Iterationsindi-

zes. Die in Listing 12.8 definierten Stride -Klassen erhohen einen Index um 1 bzw. um einen konstanten

Wert. Dieses Inkrementieren wird durch Aufruf der Methode stride durchgefuhrt.

Listing 12.8: ET-Implementierung fur die Durchfuhrung von Iterationsschritten.

template <c l a s s A>

s t r u c t LoopS t r i d e ope ra to r const A& () const ; ;

template <c l a s s A>

c l a s s P l u sP l u s : pub l i c LoopSt r i de <PlusP lus<A> >

A& a ;

pub l i c :

P l u sP l u s (A& a ) : a ( a )

vo id s t r i d e ( ) const ++(a . i t e r ( ) ) ;

;

template <c l a s s A, c l a s s B>

c l a s s PlusC : pub l i c LoopSt r i de<PlusC<A,B> >

A& a ; B b ;

pub l i c :

PlusC (A& a , const B& b ) : a ( a ) , b ( b )

vo id s t r i d e ( ) const ( a . i t e r ())+=b ;

;

Nach diesen ET-Implementierungen zur Darstellung der for-Schleifen wird in Listing 12.9 schließlich

die Index-Klasse prasentiert. Diese Index-Implementierung ist auf Integer-Werte als Indizes ausgerichtet,

prinzipiell konnen damit aber auch beliebige Index-Typen realisiert werden. Diese mussen lediglich

entsprechende Vergleichs- und Rechenoperatoren besitzen. Die zwei Versionen der Methode iter regeln

den Zugriff auf den eigentlichen Indexwer. Die Variante, die eine Referenz auf den internen iterator

zuruckgibt, wird fur Initialisierung und In- bzw. Dekrementierung benotigt, weil dabei der Indexwert

verandert wird. Die Methoden fur die Zuweisung und die In-/Dekrement-Operatoren sind in der Klasse

Index definiert, da nur an Indizes Werte zugewiesen werden konnen.

Listing 12.9: Index-Klasse fur die Schleifeniteration.

c l a s s I ndex : pub l i c IndexEpr<Index >

i n t i t e r a t o r ;

pub l i c :

I ndex ( i n t i = 0) : i t e r a t o r ( i )

i n t& i t e r ( ) r e t u r n i t e r a t o r ;

const i n t& i t e r ( ) const r e t u r n i t e r a t o r ;

. . .

I n i tC <Index , i n t > ope ra to r = ( i n t i )

i t e r a t o r = i ; r e t u r n I n i tC <Index , i n t >(∗ t h i s , i ) ;

I n i t I <Index , Index> ope ra to r = ( const I ndex& i )

i t e r a t o r = i . i t e r ( ) ; r e t u r n I n i t I <Index , Index >(∗ t h i s , i ) ;

template <c l a s s A>

I n i t I <Index , A> ope ra to r = ( const IndexEpr<A>& i )

r e t u r n I n i t I <Index ,A>(∗ t h i s , i ) ;

PlusP lus<Index> ope ra to r ++ ( i n t ) r e t u r n PlusP lus<Index >(∗ t h i s ) ;

PlusC<Index , i n t > ope ra to r += ( i n t b ) ;

;

Neben diesen ET-Implementierungen zur Initialisierung von Indizes, zum Test von Indexausdrucken

111

Page 128: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

12.2. ITERATIONSSCHLEIFEN MITTELS ET

bzw. zur In-/Dekrementierung von Indizes, konnen auf die gleiche Weise noch erganzende Operationen

eingefuhrt werden. Zusatzlich sind auch Summationen, Subtraktionen, etc. von Indizes definierbar, so

dass das Spektrum der Indexberechnungen abgedeckt werden kann.

Unter Verwendung dieser ET-Programmierungen werden nun die Klassen zur Definition der Schleifen

eingefuhrt. Dabei treten mehrere Arten von Schleifen-Typen auf, die durch den Enumerationswert

LoopLayer angegeben werden.

enum LoopLayer Outer , I nne r , B locked ;

Zur allgemeinen Kapselung der verschiedenen Typen der Iterationsschleifen enthalt Listing 12.10

mit Loop Wrapper eine Wrapper-Klasse, welche die vorher definierten Teile einer Schleife beinhaltet.

Zusatzlich sind Methoden zur Durchfuhrung der Initialisierung ( init ), des Tests ( isTrue) und der In-

/Dekrementierung ( stride ) erklart. Diese rufen die Funktionen der gespeicherten Schleifeninhalte auf.

Listing 12.10: Wrapper-Klasse der ET-Iterationsschleifen.

template<c l a s s A, c l a s s B, c l a s s C, LoopLayer l a y e r > c l a s s IndexLoop ;

template<c l a s s A> c l a s s Loop Wrapper ;

template<c l a s s A, c l a s s B, c l a s s C, LoopLayer l a y e r >

c l a s s Loop Wrapper <IndexLoop<A,B,C , l a y e r > >

t ypede f IndexLoop <A,B,C , l a y e r > LOOP;

const A& a ; const B& b ; const C& c ;

pub l i c :

Loop Wrapper ( const A& a , const B& b , const C& c ) : a ( a ) , b ( b ) , c ( c )

ope ra to r const LOOP&() const r e t u r n ∗ s t a t i c c a s t <const LOOP∗>( t h i s ) ;

vo id i n i t ( ) const a . i n i t ( ) ;

boo l i sT rue ( ) const r e t u r n b . i sT rue ( ) ;

vo id s t r i d e ( ) const c . s t r i d e ( ) ;

;

In der abschließenden Definition der Klasse IndexLoop fugen sich die vorher eingefuhrten ET-Imple-

mentierungen zusammen. Sie stellt die Schleife dar, in der die eigentliche Iteration initiiert wird. Um

eine Notation ahnlich der for-Schleife zu erhalten, wird ein entsprechendes ET-Objekt uber die Creator-

Funktion for loop erstellt, die die Schleifen-Definition als Parameter besitzt. Die Iteration wird dann

im Klammeroperator (operator()) des ET-Schleifen-Objekts durchgefuhrt. Dabei werden die gespeicher-

ten Schleifenbestandteile in eine herkommliche for-Schleife eingesetzt. Der Klammeroperator hat als

Argument ein Evaluate-Objekt, woruber die Berechnungen ausgefuhrt werden.

Listing 12.11: ET-Iterationsschleife zur Durchfuhrung einfacher Iterationen.

template<c l a s s A, c l a s s B, c l a s s C>

s t r u c t IndexLoop <A,B,C , Outer> : pub l i c Loop Wrapper<IndexLoop <A,B,C , Outer> >

t ypede f IndexLoop <A,B, C , Outer> LOOP;

IndexLoop ( const A& a , const B& b , const C& c ) ;

template <c l a s s D, c l a s s E>

vo id ope ra to r ( ) ( const Eva lua te<D,E>& ev ) const

f o r ( t h i s−> i n i t ( ) ; t h i s−>i sT rue ( ) ; t h i s−>s t r i d e ( ) )

ev . i t e r a t i o n ( ) ;

;

template <c l a s s A, c l a s s B, c l a s s C>

i n l i n e IndexLoop <A,B,C , Outer>

f o r l o o p ( const Loop In i t <A>& a , const LoopCondi t ion <B>& b , const LoopSt r i de <C>& c ) ;

Das nachfolgende Listing 12.12 prasentiert die Anwendung der so realisierten ET-Schleife. Dabei

wird eine zusatzlich definierte skalare Multiplikation von Indizes mit Vektoren verwendet.

112

Page 129: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 12. WEITERE EINSATZGEBIETE VON ET

Listing 12.12: Anwendungsbeispiel der ET-Schleifen.

I ndex J ;

f o r l o o p ( J = 0 , J < i t e r , J++)

(

b == d + 2.∗ a + J∗c

) ;

Dieser eingefuhrte Ansatz, die Iterationsschleifen in ET-Objekten zu kapseln, erweist sich als sehr

allgemein. Beispielsweise konnen durch einfache Erweiterungen auch geschachtelte Schleifen behandelt

werden.

Listing 12.13: ET-Programmierung von geschachtelten Schleifen.

template<c l a s s A, c l a s s B, c l a s s C>

s t r u c t IndexLoop <A,B,C , I nne r > :

pub l i c Loop Wrapper<IndexLoop <A,B,C , I nne r > >

t ypede f IndexLoop <A,B,C , I nne r > LOOP;

IndexLoop ( const A& a , const B& b , const C& c )

: Loop Wrapper<LOOP> ( a , b , c )

template <c l a s s D, c l a s s E>

Eva lua te<LOOP, Eva lua te<D,E> >

ope ra to r ( ) ( const Eva lua te<D,E>& ev ) const

r e t u r n Eva lua te<LOOP, Eva lua te<D,E> >(∗ t h i s , ev ) ;

;

template <c l a s s A, c l a s s B, c l a s s C>

i n l i n e IndexLoop<A,B,C , I nne r >

f o r ( const Loop In i t <A>& a , const LoopCondi t ion <B>& b , const LoopSt r i de<C>& c )

r e t u r n IndexLoop <A,B,C , I nne r >(a , b , c ) ;

Dazu wird in Listing 12.13 die ET-Implementierung einer inneren Schleife aufgefuhrt. Im Grunde

unterscheidet sich diese nur durch den anders definierten Klammeroperator von der außeren Schlei-

fenklasse. Fur innere Schleifen erzeugt der Klammeroperator ein weiteres Evaluate-Objekt, welches die

Schleife selbst und den Schleifenrumpf speichert. D.h., die Ausfuhrung der inneren Schleife wird wie-

derum verzogert. Die Creator-Funktion for erzeugt das entsprechende IndexLoop-Objekt.

In Erganzung zu Listing 12.13 zeigt das nachfolgende Listing 12.14 die Spezialisierung der Evaluate-

Klasse, die fur den Fall definiert ist, bei dem die erste Komponente eine innere ET-Schleife ist. Dabei

wird in der Methode iteration die for-Schleife mit den Parametern der gespeicherten Schleife ausgefuhrt.

Mit dieser Spezialisierung der Evaluate-Klasse konnen beliebig viele ET-Schleifen geschachtelt werden.

Die Iterationen werden dann sukzessive uber die außerste Schleife ausgefuhrt.

Listing 12.14: ET-Klasse zur Kapselung der inneren Schleifen.

template<c l a s s A, c l a s s B, c l a s s C , c l a s s E>

c l a s s Eva lua te<IndexLoop<A,B,C , I nne r >,E>

t ypede f IndexLoop <A,B,C , I nne r > LOOP;

const LOOP& loop ;

const E& ev ;

pub l i c :

E v a l ua t e ( const LOOP& l , const E& ev ) : l oop ( l ) , ev ( ev )

vo id i t e r a t i o n ( ) const

f o r ( l oop . i n i t ( ) ; l oop . i sT rue ( ) ; l oop . s t r i d e ( ) )

ev . i t e r a t i o n ( ) ;

;

Listing 12.15 zeigt die Anwendung der geschachtelten ET-Schleifenaufrufe. Dabei wird mit der

Creator-Funktion for ein inneres Schleifenobjekt erzeugt.

113

Page 130: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

12.3. ET-SCHLEIFENBLOCKING MIT NUMMERIERTEN VARIABLEN

Listing 12.15: Geschachtelte Anwendung der ET-Schleifen.

I ndex J , K;

f o r l o o p ( J = 0 , J < i t e r , J++)

(

f o r (K = J , K < i t e r , K++)

(

d == b + J∗a + K∗ c

)

) ;

Mit den prasentierten Implementierungen lassen sich Iterationsschleifen in ET-Ausdrucke umwan-

deln. Die resultierenden ET-Objekte werden beim Ubersetzen optimiert, so dass die resultierenden

Programme die gleiche Leistung wie Implementierungen mit herkommlichen for-Schleifen erbringen.

In der jetzigen Form fuhren die ET-Schleifen die Iterationen in der gleichen Reihenfolge wie die ei-

gentlichen for-Schleifen durch. Doch kann aufbauend auf dieser Implementierung ein Schleifenblocking

realisiert werden.

12.3 ET-Schleifenblocking mit nummerierten Variablen

Da die numerische Simulation realistischer Problemstellungen in großen Gleichungssystemen mundet,

werden effiziente Losungsalgorithmen benotigt, um annehmbare Berechnungszeiten zu erhalten. Eine

Moglichkeit die Laufzeiten der Algorithmen zu verkurzen, besteht in der Erhohung der Speichereffizi-

enz [Kow04]. Dabei wird versucht, die Datenlokalitat im Cache zu verbessern, indem der verwendete

Speicher in Blocke aufgeteilt wird, die in den Cache passen. Vor allem bei den schwach besetzten

Matrizen, die aus der Diskretisierung partieller Differentialgleichungen resultieren, ist dies sinnvoll.

Dabei verknupfen die diskretisierten Differentialoperatoren nur geometrisch benachbarte Punkte, so

dass zur einer Berechnung eines Eintrags lediglich geringe Datenmengen benotigt werden. Die Große

der behandelbaren Blocke hangt dabei von der Cache-Große, sowie von der Anzahl der Variablen im

zu berechnenden Ausdruck ab.

Da durch die ET-Implementierungen Ausdrucksbaume erzeugt werden, kann aus diesen bestimmt

werden, wie viele verschiedene Variablen im jeweiligen Ausdruck vorkommen. Dies kann mit herkomm-

lichen Vektor-Klassen realisiert werden, indem bei jedem Konstruktoraufruf ein neuer Index vergeben

wird. Dieser wird intern gespeichert, so dass damit mittels Durchlauf durch die Ausdrucksbaume die

Anzahlen der darin verschiedenen Vektoren bestimmt werden konnen.

Nachfolgende Programmierung basiert jedoch auf den template-nummerierten Vektoren der FET-

Variante (Listing 6.1), da hier ein solcher Index bereits in den Typen der Vektoren gegeben ist. Dadurch

sind die Informationen uber die verschiedenen Vektoren in einem Ausdruck bereits zur Ubersetzungszeit

bekannt. Um die Anzahl der unterschiedlichen Vektoren auch bereits beim Compilieren bestimmen zu

konnen, werden die Vektoren der Ausdrucke in sog. type lists gespeichert [Ale01]. Eine entsprechende

Implementierung findet sich in Anhang C. Von einer solchen Typliste kann dann nach dem Loschen

der Duplikate die Lange bestimmt werden, welche die Anzahl der verschiedenen Variablen angibt.

Als Beispiel fur die erforderlichen Erweiterungen zeigt das nachfolgende Listing 12.16 die Definition

des Typs VARIABLE LIST in der Additionsklasse. Dabei werden die Typlisten der beiden Operanden

zusammengefasst. Passend dazu wird in der Klasse Vector (Listing 12.17) eine Typliste initialisiert.

Listing 12.16: Typlist-Definition in der Additionsklasse.

template <c l a s s A, c l a s s B>

c l a s s Add : pub l i c Expr<Add<A,B> > . . .

t ypede f typename Jo in<typename A : : VARIABLE LIST ,

typename B : : VARIABLE LIST > : : LIST VARIABLE LIST ;

;

114

Page 131: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 12. WEITERE EINSATZGEBIETE VON ET

Um die Auswertung von Vektorausdrucken in Blocken durchfuhren zu konnen, wird in der Klasse

Vector zusatzlich eine Methode evaluateBlock definiert. Diese wertet den ubergebenen Ausdruck nur vom

Index start bis end aus.

Listing 12.17: Erweiterung der Vektorklasse zur Durchfuhrung des Blockings.

template < i n t un ique I d >

c l a s s Vector : pub l i c Expr<Vector <un ique I d > > . . .

t ypede f TYPELIST ( Vector <num>) VARIABLE LIST ;

template<c l a s s A>

vo id e v a l ua t eB l o ck ( const Expr<A>& a , i n t s t a r t , i n t end )

const A& a ( a ) ;

f o r ( i n t i = s t a r t ; i < end ; ++i )

da ta [ i ] = a . g i v e ( i ) ;

;

Dem entsprechend wird in der Klasse Evaluate eine Methode zur Iteration uber die Blocke eingefuhrt

( iteration in Listing 12.18). Die Funktion size gibt die Große des Ergebnisvektors zuruck.

Listing 12.18: Erweiterung der Evaluate-Klasse fur Schleifenblocking.

template <c l a s s A, c l a s s B>

c l a s s Eva l ua t e

A& a ; const B& b ;

. . .

i n t s i z e ( ) const r e t u r n a . s i z e ( ) ;

vo id i t e r a t i o n ( i n t s t a r t , i n t end ) const

a . e v a l ua t eB l o ck (b , blocknumber , b l o c k s i z e ) ;

;

Schließlich zeigt Listing 12.19 die Implementierung der geblockten ET-Schleife. In der Methode

operator() wird in Zeile 9 die Anzahl der unterschiedlichen Vektorvariablen bestimmt. Daraus werden in

den Zeilen 10 und 11 uber die Lange der Vektoren und die Cachegroße ( CACHESIZE ) die Anzahl und

Große der Schleifenblocke bestimmt. In der darauf folgenden for-Schleife werden die Blocke abgearbei-

tet, und abschließend der letzte Block, der im Allgemeinen kleiner ist als die vorherigen Blocke.

Listing 12.19: ET-Iterationsschleife zur Durchfuhrung des Blockings.

template<c l a s s A, c l a s s B, c l a s s C>

s t r u c t IndexLoop <A,B,C , Blocked> :

pub l i c Loop Wrapper<IndexLoop <A,B,C , Blocked> >

t ypede f IndexLoop <A,B, C , Blocked> LOOP;

5 IndexLoop ( const A& a , const B& b , const C& c ) : Loop Wrapper<LOOP>(a , b , c )

template <c l a s s D, c l a s s E>

vo id ope ra to r ( ) ( const Eva lua te<D,E>& ev ) const

i n t i =0, n rVa r s=CountVar i ab l e s <D,E> : : v a l ue ,

n rB l o ck s=(ev . s i z e ( )∗ nrVa r s )/ CACHESIZE +1, b l o c k s i z e=ev . s i z e ( )/ n rB l o ck s ;

10 f o r ( i = 0 ; i < n rB l o ck s ; ++i )

i n t s = i ∗ b l o c k s i z e , end = s+b l o c k s i z e ;

f o r ( t h i s−> i n i t ( ) ; t h i s−>i sT rue ( ) ; t h i s−>s t r i d e ( ) )

ev . i t e r a t i o n ( s , end ) ;

15 f o r ( t h i s−> i n i t ( ) ; t h i s−>i sT rue ( ) ; t h i s−> s t r i d e ( ) )

ev . i t e r a t i o n ( i ∗ b l o c k s i z e , ev . s i z e ( ) ) ;

;

template <c l a s s A, c l a s s B, c l a s s C2>

20 i n l i n e IndexLoop<A,B,C , Blocked>

f o r b l o c k e d ( const Loop In i t <A>& a , const LoopCondi t ion <B>& b , const LoopSt r i de<C>& c ) ;

115

Page 132: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

12.3. ET-SCHLEIFENBLOCKING MIT NUMMERIERTEN VARIABLEN

Die in Listing 12.19 prasentierte Version des Schleifenblockings verwendet keine Uberlappung der

Schleifen. Die Creator-Funktion for blocked erzeugt die geblockte ET-Schleife.

Das mit dieser Implementierung realisierte Schleifenblocking kann wie die vorherigen Schleifen im

Anwendercode verwendet werden. Beispielsweise zeigt Listing 12.20 die Berechnung des Gauß-Seidel-

Losers unter der geblockten Schleifeniteration.

Listing 12.20: Anwendercode des geblockten Gauß-Seidel-Losers.

I ndex J ;

f o r b l o c k e d ( J = 0 , J < i t e r , J++)

(

u == 0.25 ∗ ( 1 . / ( h∗h ) ∗ b + N(u ) + S(u ) + W(u ) + E(u ) ) ;

) ;

Die prasentierten ET-Implementierungen lassen sich auch auf while-Schleifen und allgemeinere Be-

dingungen erweitern. Dadurch konnen in den Bedingungsabfragen nicht nur Indizes verwendet werden,

sondern z.B. auch eine Vektornorm. Dies eroffnet ein breites Anwendungsfeld einer solchen Kapselung

von Schleifen in ET-Ausdrucken.

Abschließend zeigt Abbildung 12.1 die Effizienz der erhaltenen ET-Blocking-Programmierungen.

Darin werden ein C-Code ohne Blocking, eine C-Version mit Schleifenblocking sowie die prasentier-

te ET-Schleifenblocking-Implementierung verglichen. Als Anwendung dient der Gauß-Seidel-Loser fur

das zweidimensionale Poisson-Problem, durchgefuhrt auf einer Pentium 4 Workstation (Anhang D.1.1),

ubersetzt mit dem GNU-Compiler (Version 4.1.0). Zum Vergleich der Resultate werden hierzu nicht

die Zeiten pro Iteration betrachtet, sondern die Ausfuhrungszeiten die benotigt werden, um ein Ergeb-

nis mit vorgegebener Genauigkeit zu erhalten. Wahrend die Implementierung ohne Blocking deutlich

schlechter wird, sobald die gemeinsamen Datenmengen der Vektoren die Cache-Große ubersteigt, be-

sitzen die anderen Versionen ein gleichbleibendes Performance-Verhalten.

Abbildung 12.1: Performance-Vergleich des Gauß-Seidel-Losers implementiert in C-Code ohne

Blocking, C-Code mit Blocking und ET-Schleifen-Blocking.

116

Page 133: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 13. ABSCHLIESSENDE BEMERKUNGEN

13 Resumee und abschließende Bemerkungen

Die ET-Implementierungstechnik beschreibt eine interessante und vielseitig einsetzbare Methode zur

Realisierung effizienter Programme. Die Darstellung von Ausdrucksbaumen mittels templatisierter

Klassen ermoglicht den C++-Compiler weitreichende Optimierungsmoglichkeiten.

13.1 Zusammenfassung

Die Ergebnisse der vorliegenden Arbeit beinhalten gundlegende Weiterentwicklungen der ET-Technik

selbst, und zeigen den anwendungsbezogenen Einsatz der erarbeiteten Implementierungsstrategien zur

numerischen Losung partieller Differentialgleichungen.

13.1.1 Einfache und Leistungsstarke ET-Implementierungen

Aufbauend auf den grundlegenden Untersuchungen in Kapitel 4 konnten ET-Implementierungen pra-

sentiert werden, die einfach und kurz zu realisieren sind (Kapitel 5). Dies war einerseits eine ET-

Version fur lokal benutzte ET-Objekte, sowie eine Variante zum Abspeichern und Wiederverwenden

von ET-Ausdrucken. Diese strukturierte Betrachtung und Darstellung der ET-Technik ermoglichte die

vielfaltigen Anwendungen in Teil III der vorliegenden Arbeit. Gerade die vereinfachte Programmierung

und die genaue Analyse der Gultigkeitsdauer der ET-Objekte vermeiden die haufigsten Fehlerquellen

wahrend der Software-Entwicklung.

Zusatzlich werden mit den weiterentwickelten FET-Techniken die bestehenden Performance-Proble-

me der ET-Varianten gelost. Durch die eindeutige Template-Nummerierung der Vektorvariablen wer-

den die Compiler bei der Durchfuhrung der Optimierungen entscheidend unterstutzt. Somit erreichen

FET-Implementierungen auch auf Hoch- und Hochstleistungsrechnern die Peformance vergleichbarer

Programme im C-Stil. Dies ermoglicht ET-Anwendungen, die auf Arbeitsplatzrechnern entwickelt wur-

den, nahezu identisch auf Hochleistungsrechner zu ubertragen, und dennoch die plattformspezifische

Rechenleistung voll nutzen zu konnen. Gerade mit der Zielsetzung die ET-Technik zur numerischen

Losung partieller Differentialgleichungen einzusetzen, ist dies eine entscheidende Verbesserung zu den

herkommlichen ET-Varianten. Denn die aus der Diskretisierung von realistischen Problemstellungen

resultierenden großen Gleichungssysteme machen den Einsatz von Hochleistungsplattformen oft un-

umganglich.

13.1.2 ET zum Losen von partiellen Differentialgleichungen

Die appoximative Berechnung partieller Differentialgleichungen basiert auf der Implementierung vie-

ler komplexer Datenstrukturen und Rechenoperationen. Dies erstreckt sich von der Erstellung der

Diskretisierungsgitter bis zur Anwendung entsprechender Losungsalgorithmen fur die resultierenden

Gleichungssysteme. Wegen der zusatzlichen Forderung nach effizienten Implementierungen bietet sich

zur Realisierung solcher Bibliotheken C++, als Sprache mit programmiersprachlichen Mitteln zur mo-

dularen und effizienten Programmierung, an. Daruber hinaus ermoglicht C++ mit dem Uberladen

von Operatoren eine benutzerfreundliche und intuitive Realisierung mathematischer Problemstellun-

gen. Dadurch konnen die teilweise komplexen Berechnungsvorgange, die sich hinter den Operationen

stecken, vor den Anwendern verborgen werden.

117

Page 134: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

13.2. WEITERE ENTWICKLUNGEN UND AUSBLICK

Die effiziente Implementierung der uberladenen mathematischen Operatoren kann mit ET erreicht

werden. Die dabei generierten Ausdrucksbaume erlauben auf Grund der durchgangigen Typinformation

ein vollstandiges Inlining der Funktionsaufrufe bei der Auswertung. Somit resultieren leistungsstarke

Programme, die auch fur komplizierte Datenstrukturen und Formeln performante Losungen bieten.

Die Template-Bibliothek Colsamm (Kapitel 11) demonstrierte dazu, wie durch die Kombination

mehrerer ET- bzw. FET-Implementierungen auch abstrakte Objekte wie Finite Elemente sehr ma-

thematisch modelliert werden konnen. Mittels einer durchdachten Verknupfung von Template- und

ET-Techniken mit der traditionellen Datenkapselungen sind somit effiziente und flexible Bibliotheken

realisierbar. Aufbauend auf dem strukturierten Programmablauf von Colsamm, der unnotige Berech-

nungen verhindert, konnten die notwendigen Funktionalitatseinheiten herausgearbeitet und modular

programmiert werden. Diese und die zugrunde liegenden mathematischen Formulierungen lieferten

konkrete Ansatze fur den Einsatz der ET-Implementierungen. Dabei ermoglichten die weitreichen-

den Untersuchungen und Verbesserungen der ET-Technik im Teil II dieser Arbeit eine unmittelbare,

problemnahe Realisierung der mathematischen Schnittstellen.

Zusatzlich ergeben sich aus den prasentierten ET- und FET-Techniken weiterfuhrende Anwen-

dungsmoglichkeiten, die uber die Darstellung mathematischer Ausdrucksbaume und Terme hinaus-

gehen. Dies zeigte beispielsweise die Kapselung von for-Schleifen in ET-Ausdrucken in Abschnitt 12.2.

Dabei wurden durch den Einsatz von mehreren ET-Implementierungen die Bestandteile von Iterati-

onsschleifen in gesonderte ET-Objekte umgewandelt, um so schleifenubergreifende Optimierungen und

leistungsverbessernde Schleifentransformationen explizit durchfuhren zu konnen.

13.2 Weitere Entwicklungen und Ausblick

Aus den Ergebnissen der vorliegenden Arbeit eroffnen sich weite Anwendungsmoglichkeiten der ET-

Technik zum Losen von partiellen Differentialgleichungen. Prinzipiell bietet nahezu jede Abstraktions-

stufe in PDG-Bibliotheken einen Ansatzpunkt fur den Einsatz entsprechender ET-Mechanismen.

Die ET-Implementierungen eignen sich zur effizienten Realisierung der mathematischen Operatio-

nen. Dies war Ziel des Ansatzes von Veldhuizen, und spiegelt auch die große Menge der Einsatzgebiete

von ET wider. Dabei besteht die Leistung der ET-Technik in der Kapselung der Ausdrucke als Typ-

informationen, was den C++-Compilern umfassende Optimierungsmoglichkeiten bietet. Doch konnen

ET nicht nur fur offensichtliche Ansatze wie die Addition, Subtraktion, etc. von (mathematischen)

Objekten eingesetzt werden. Denkbar sind auch Implementierungen, welche die Operatoren bzgl. der

problemspezifischen Anwendung mit komplett neuer Bedeutung definieren. So konnen beispielsweise

die logischen Operatoren & und | verwendet werden, um Vektoren oder Matrizen sehr intuitiv pro-

grammieren zu konnen.

Prinzipiell ausbaufahiger ist jedoch eine Verwendung von ET, die uber die Grenzen der semantischen

Ausdrucke hinaus geht. Dies umfasst einerseits das abspeichern von ET-Objekten (Abschnitt 7.3). In

den meisten bestehenden Bibliotheken und Anwendungen werden die ET-Ausdrucke nur direkt bei

ihrer Erstellung verwendet. Doch durch eine entsprechende Speicherung konnen die ET-Objekte auch

an nachfolgenden Stellen im Programm mit gleichbleibenden Optimierungsmoglichkeiten genutzt wer-

den. Naturlich nur, wenn die ET-Ausdrucke mit ihrer vollen Typinformation ohne abstrakte Klassen

abgespeichert sind. Daraus eroffnet sich unmittelbar ein Einsatz von ET zur Programmierung von

wiederverwendbaren Formeln, die wiederholt fur wechselnde Daten ausgewertet werden mussen. Dies

wurde beispielsweise bei der Realisierung der Template-Bibliothek Colsamm zur effizienten Implemen-

tierung der Transformationsformeln verwendet.

Die großten und vielfaltigsten Entwicklungsmoglichkeiten bestehen jedoch beim Einsatz von ET-

Implementierungen zur erweiterten Optimierung ganzer Anweisungsblocke. Dies zeigte beispielsweise

die Kapselung der for-Schleifen mittels ET-Objekten zur automatischen Durchfuhrung von benutzer-

gesteuerten Optimierungen (behandelt in Abschnitt 12.2). Dabei kann die eigentliche programmier-

118

Page 135: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

KAPITEL 13. ABSCHLIESSENDE BEMERKUNGEN

sprachliche Syntax und Semantik von C++ zwar nicht exakt, aber sehr ahnlich imitiert werden. Dieser

Ansatz kann entsprechend auch fur weitere Programmeinheiten verwendet werden, in denen durch

Kapselung ausdrucksubergreifender Informationen weiterfuhrende Transformationen des eigentlichen

Programmcodes moglich sind bzw. zusatzliche Optimierungen durchgefuhrt werden konnen. Dadurch

sind grundsatzlich Implementierungen von domain specific embedded languages (DSEL) denkbar – und

C++-Bibliotheken zur numerischen Losung partieller Differentialgleichungen sind prinzipiell DSELs

– deren Anwendungen aus mehreren ET-Objekten bestehen, die bestimmte Programmeinheiten kap-

seln. Diese erlauben dann die explizite Durchfuhrung von DSEL-spezifischen Optimierungen, welche

die C++-Compiler bei herkommlichen Implementierungen selbst nicht erreichen konnen.

Somit eroffnet die ET-Technik gerade fur das wissenschaftliche Rechnen eine Vielzahl von Einsatzge-

bieten. Den Entwicklern stehen leistungsstarke Mechanismen zur Realisierung der jeweilig passenden,

benutzerfreundlichen sowie effizienten DSEL zur Verfugung, die auf Grund der Ergebnisse der vorlie-

genden Arbeit einfach und intuitiv implementiert werden konnen.

119

Page 136: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

13.2. WEITERE ENTWICKLUNGEN UND AUSBLICK

120

Page 137: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

Teil IV

Anhang

Page 138: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen
Page 139: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG A. ET-IMPLEMENTIERUNG NACH VELDHUIZEN

A ET-Implementierung nach Veldhuizen

Die Einfuhrung der ET-Implementierungstechnik von Veldhuizen in [Vel95] revolutionierte das Ope-

ratoruberladen in C++. Um einen Eindruck der Entwicklungen in der vorliegenden Arbeit zu bieten,

wird in diesem Kapitel die erste von Veldhuizen veroffentlichte Implementierungsvariante erortert. Die

nachstehenden Programmcodes sind aus [Vel98] entnommen.

Listing A.1: Vektor-Klasse der ET-Implementierung nach Veldhuizen.

c l a s s DVec ;

s t r u c t DVecAss ignable

v i r t u a l vo id a s s i g n (DVec&) const = 0 ;

;

c l a s s DVec

p r i v a t e :

double ∗ data ;

i n t l e n g t h ;

pub l i c :

t ypede f double ∗ i t e rT ;

t ypede f double elementT ;

DVec( i n t n ) : l e n g t h ( n ) data = new double [ n ] ;

˜DVec ( ) de l e t e [ ] da ta ;

double& ope ra to r [ ] ( i n t i ) r e t u r n data [ i ] ;

i t e rT beg in ( ) const r e t u r n data ;

i t e rT end ( ) const r e t u r n data + l e n g t h ;

i n t l e ng th ( ) const r e t u r n l e n g t h ;

DVec& ope ra to r=(const DVecAss ignable& x )

x . a s s i g n (∗ t h i s ) ; r e t u r n ∗ t h i s ;

;

Dazu prasentiert das Listing A.1 die Implementierung der Vektor-Klasse (hier DVec). Im damaligen

C++-Standard waren noch keine Member-Templates zugelassen, d.h. die Definition von templati-

sierten Membermethoden war nicht moglich. Aus diesem Grund wurde bei der Programmierung des

Zuweisungsoperators uber die abstrakte Klasse DVecAssignable eine Schnittstelle fur die ET-Ausdrucke

geschaffen. Der dabei auftretende virtuelle Funktionsaufruf bei der Auswertung tritt nur in der außers-

ten Schicht eines Ausdrucks auf. Die restlichen Funktionsaufrufe konnen mittels Inlining optimiert

werden.

Um in den ET-Ausdrucken keine Vektorobjekte kopieren zu mussen, werden nur die Datenzeiger

abgespeichert. Aus diesem Grund sind die Funktionen begin und end sowie der Typ iterT definiert.

Die Funktion assignResult in Listing A.2 beschreibt die globale templatisierte Auswertungs- und Zu-

weisungsfunktion. Dabei sind uber Makros unterschiedliche Auswertungsvarianten fur verschiedene

Plattformen definiert. Zusatzlich zeigt Listing A.2 die Implementierung der Wrapper-Klasse (DVExpr).

Dabei werden im Wrapper volle Objekte abgespeichert, die somit beim Aufbau mehrfach kopiert wer-

den mussen. Weiter definiert die Klasse DVExpr als Ableitung der abstrakten Klasse DVecAssignable die

virtuelle assign-Methode. Diese ruft die globale Funktion assignResult auf.

123

Page 140: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG A. ET-IMPLEMENTIERUNG NACH VELDHUIZEN

Listing A.2: Funktion zur Auswertung und Zuweisung von ET-Objekten.

template<c l a s s I t e r >

vo id a s s i g nR e s u l t (DVec& a , const I t e r& r e s u l t )

#i f d e f EXPRVEC USE TEMPORARY EXPRESSION

// Make a temporary copy o f the i t e r a t o r . Thi s i s f a s t e r on segmented

// a r c h i t e c t u r e s , s i n c e a l l the i t e r a t o r s a r e i n the same segment .

I t e r r e s u l t 2 = r e s u l t ;

#e l s e

// Otherwise , c a s t away cons t ( eek ! ) . No ha rmfu l s i d e e f f e c t s .

I t e r& r e s u l t 2 = ( I t e r &) r e s u l t ;

#e n d i f

#i f d e f EXPRVEC USE INDIRECTION

double ∗ i t e r = a . beg in ( ) ;

f o r ( r e g i s t e r i n t i = a . l e ng th ( ) ; i −−;)

i t e r [ i ] = r e s u l t 2 [ i ] ; // I n l i n e d e x p r e s s i o n

#e l s e

double ∗ i t e r = a . beg in ( ) ;

double ∗ end = a . end ( ) ;

do

∗ i t e r = ∗ r e s u l t 2 ; // I n l i n e d e x p r e s s i o n

++r e s u l t 2 ;

wh i l e (++ i t e r != end ) ;

#e n d i f

template<c l a s s A>

c l a s s DVExpr : pub l i c DVecAss ignable

A i t e r ;

pub l i c :

DVExpr ( const A& a ) : i t e r ( a )

double ope ra to r ∗ ( ) const r e t u r n ∗ i t e r ;

double ope ra to r [ ] ( i n t i ) const r e t u r n i t e r [ i ] ;

vo id ope ra to r++() ++i t e r ;

// V i r t u a l f u n c t i o n from DVecAss ignable . C a l l e d by

// DVec : : ope r a to r =(DVecAss ignable &).

v i r t u a l vo id a s s i g n (DVec& x ) const a s s i g nR e s u l t ( x , ∗ t h i s ) ;

;

Schließlich folgt die Programmierung der Additionklasse und der Operatoren. Die Addition wird als

Spezialfall der binaren Operationsklasse DVBinExprOp eingefuhrt. Diese Klasse speichert die Operanden

als volle Objekte. Die uberladenen Operatoren, die in vier Varianten zu definieren sind, erzeugen

daraus die entsprechenden Additionsobjekte. Im Falle von Vektoren als Operanden werden jedoch

die internen Pointer der Vektoren gespeichert. Somit wird das unnotige Kopieren der Vektor-Klasse

umgangen. Dabei ist jedoch zu bemerken, dass die Implementierung der Operatoren auf Grund der

geschachtelten Template-Konstrukte sehr komplex wird.

124

Page 141: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG A. ET-IMPLEMENTIERUNG NACH VELDHUIZEN

Listing A.3: Operationsklassen und Operatoren der ursprunglichen ET-Variante

s t r u c t DApAdd

s t a t i c i n l i n e double app l y ( double a , double b ) r e t u r n a+b ;

;

template<c l a s s A, c l a s s B, c l a s s Op>

c l a s s DVBinExprOp

A i t e r 1 ; B i t e r 2 ;

pub l i c :

DVBinExprOp( const A& a , const B& b) : i t e r 1 ( a ) , i t e r 2 (b )

vo id ope ra to r++() ++i t e r 1 ; ++i t e r 2 ;

double ope ra to r ∗ ( ) const r e t u r n Op : : app l y (∗ i t e r 1 ,∗ i t e r 2 ) ;

double ope ra to r [ ] ( i n t i ) const

r e t u r n Op : : app l y ( i t e r 1 [ i ] , i t e r 2 [ i ] ) ;

;

DVExpr<DVBinExprOp<double ∗ , double ∗ ,DApAdd> >

ope ra to r+(const DVec& a , const DVec& b )

t ypede f DVBinExprOp<double ∗ , double ∗ ,DApAdd> ExprT ;

r e t u r n DVExpr<ExprT>(ExprT ( a . beg in ( ) , b . beg in ( ) ) ) ;

template<c l a s s A>

DVExpr<DVBinExprOp<DVExpr<A>,double ∗ ,DApAdd> >

ope ra to r+(const DVExpr<A>& a , const DVec& b )

t ypede f DVBinExprOp<DVExpr<A>,double ∗ ,DApAdd> ExprT ;

r e t u r n DVExpr<ExprT>(ExprT ( a , b . beg in ( ) ) ) ;

template<c l a s s A>

DVExpr<DVBinExprOp<double ∗ ,DVExpr<A>,DApAdd> >

ope ra to r+(const DVec& a , const DVExpr<A>& b)

t ypede f DVBinExprOp<double ∗ ,DVExpr<A>,DApAdd> ExprT ;

r e t u r n DVExpr<ExprT>(ExprT ( a . beg in ( ) , b ) ) ;

template<c l a s s A, c l a s s B>

DVExpr<DVBinExprOp<DVExpr<A>,DVExpr<B>,DApAdd> >

ope ra to r+(const DVExpr<A>& a , const DVExpr<B>& b)

t ypede f DVBinExprOp<DVExpr<A>,DVExpr<B>,DApAdd> ExprT ;

r e t u r n DVExpr<ExprT>(ExprT ( a , b ) ) ;

125

Page 142: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG A. ET-IMPLEMENTIERUNG NACH VELDHUIZEN

126

Page 143: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

B Colsamm – Programmstruktur

In diesem Kapitel werden einige grundlegende Implementierungsdetails zur Bibliothek Colsamm er-

lautert. Da die problemspezifischen Parameter der Finiten Elemente (siehe Abschnitt 11.1.1) zum Teil

unterschiedliche Berechnungsmechanismen zur Folge haben, wurde Colsamm als Template-Bibliothek

aufgebaut.

B.1 Template-Bibliotheken

Die Strategie bei der Entwicklung einer Template-Bibliothek besteht in der Kapselung moglichst vieler

Teile der objektspezifischen Parameter in Templates sowie spezialisierte Klassendeklarationen. Dadurch

werden zur Ubersetzungszeit die, von den gewahlten Template-Argumenten abhangigen, Instantiierun-

gen ausgewahlt, und konnen unter Einbeziehung aller Optimierungen compiliert werden. Somit entste-

hen keine uberflussigen Fallunterscheidungen zur Laufzeit. Des Weiteren werden nur die fur die aktu-

elle Anwendung benotigten Codeteile instantiiert und optimiert, nicht die gesamte Bibliothek. Diese

Template-Parameter und Spezialisierungen haben jedoch zu Folge, dass fur wechselnde Parameter neue,

entsprechend instantiierte Klassen verwendet werden mussen. Die Template-Parameter konnen nicht

dynamisch verandert werden (etwa uber ein entsprechendes Config-File). Bei einer Verwendung von

Template-Bibliotheken werden anstatt einer Erzeugung von Klassenobjekten entsprechende Template-

Instantiierungen generiert. Aus diesem Grund ist jedoch immer der gesamte Quellcode einzubinden,

und es konnen keine vorcompilierten Objektdateien erstellt werden.

Eine gangige Technik bei der Implementierung einer Template-Bibliothek ist die Verwendung der

template-gesteuerten Vererbung. Dabei werden die Template-Argumente der Basisklasse durch die

Template-Parameter der abgeleiteten Klasse definiert, siehe auch Abschnitt 2.3.5. Damit konnen bei

entsprechend angelegten Abhangigkeiten die fur die aktuelle Problemstellung notwendigen Klassen in

einer oder mehreren abgeleiteten Klassen zusammengefugt werden.

B.2 Programmstruktur

Aus der Definition von Finiten Elementen ergeben sich, erganzt durch PDG-spezifische Informationen

wie etwa Dimension, die Funktionseinheiten und Abhangigkeiten, die eine modulare Programmierung

einer flexiblen der FEM-Diskretisierung ermoglichen (siehe Abschnitt 11.1.1). Nach den Methoden der

vorher beschrieben Vererbung mit Template-Parametern wurde Colsamm um eine zentrale Domain -

Klasse implementiert, die mit den entsprechenden Template-Parametern von den Funktionseinheiten

(den Funktionsklassen) erbt. Benutzerdefinierte Finite Elemente werden dann von der Domain -Klasse

mit den gewunschten Parametern abgeleitet, erben also die Methoden der Basisklassen. Zur Verein-

fachung dieser Definitionen – es sollen nicht jedes mal alle Template-Parameter spezifiziert werden –

sind fur bestimmte Kategorien von Elementen Ableitungen der Klasse Domain eingefuhrt, die bereits

fur gewisse Kategorien einen Teil der Templates festsetzen (siehe Abschnitt B.2.7). Abbildung B.1

beschreibt den generellen Aufbau der Klassenhierarchie in Colsamm.

127

Page 144: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

Abbildung B.1: Klassenhierarchie von Colsamm.

B.2.1 Domain

Wie aus der Abbildung B.1 deutlich wird, laufen die Funktionalitaten der funf Basisklassen in Domain

zusammen. Diese Klasse erbt die Methoden und nutzt die jeweilige template-abhangige Implemen-

tierung der Formeln bzw. der Speicherverwaltung der jeweiligen Basisklassen. Zur Steuerung dieser

Template-Vererbung besitzt Domain insgesamt zwolf Template-Parameter, die wie folgt angeordnet

sind.

Listing B.1: Liste der Template-Parameter der Klasse Domain .

template < uns igned i n t co rne r sOfE l ement ,

DIMENSION i n i t d im e n s i o n ,

c l a s s TRAFO,

d oma i n S e c i f i c a t i o n i n t e r i o r I b o u n d a r y ,

uns igned i n t numberOfBas i sFunct ions ,

uns igned i n t numberOfBas i sFunct ions2 ,

ElementType elType ,

I n t e g r a t i o nA c c u r a c y intAcc ,

typename ETYPE,

s t e n c i l T y p e STENCIL ,

typename eTYPE ,

Bas i sFunct i onType BFnType>

c l a s s Domain ;

Im Folgenden werden diese Template-Argumente genauer erlautert, insbesondere welchen Auswir-

kungen und Eigenschaften diese fur die Funktionsweise von Colsamm haben.

• unsigned int cornersOfElement: die Anzahl der Diskretisierungspunkte, die fur die jeweilige Transfor-

mation benotigt werden, um ein allgemeines Element zu definieren. Dies konnen im Falle von

isoparametrischen Elementen mehr als die Anzahl der Eckpunkte des Referenzelements sein. Da-

gegen sind auch weniger Diskretisierungspunkte moglich, etwa bei regularen Wurfeln, wo vier

anstatt acht Punkte genugen um die Transformationen zu bestimmen.

• DIMENSION init dimension: Enumerationstyp mit den Werten D1, D2, D3, beschreibt die Dimension

des Elements. Diese Dimension bezieht sich auf die allgemeinen Elemente des Problems, nicht

die des Referenzelements. Also besitzen die Oberflachendreiecke im dreidimensionalen auch Di-

mension drei (D3), das Referenzelement (Unit Triangle ) ist aber zweidimensional.

• class TRAFO: stellt einen allgemeinen Template-Typen dar, der einen FET-Ausdruck mit Wrapper

VertexExpr<.> benotigt. Diese Ausdrucke entstehen durch die Kombination von Punkten und raum-

lichen Variablen mit einer anschließenden Typkapselung mittels dem Makro Define Transformation,

siehe auch 11.4.1.

128

Page 145: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

• domainSpecification interiorIboundary umfasst einen Enumerationstyp mit den Werten interior oder

boundary. Diese Werte dienen zur Unterscheidung von Elementen im Inneren bzw. am Rand, da

jeweils andere Integrationsformeln verwendet werden mussen, siehe Abschnitt 10.1.4. Im Falle von

inneren Elementen sind dies die Transformationsformel mit der Multiplikation der Determinanten

der Jacobi-Matrix. Bei Randelementen wird das Integral mittels Einsetzen der Parametrisierung

und Multiplikation mit der Lange der Parametrisierung berechnet.

• unsigned int numberOfBasisFunctions und unsigned int numberOfBasisFunctions2 bezeichnen die Anzah-

len der Basisfunktionen in den Funktionenmengen. Dabei muss die erste dieser beiden Mengen

(numberOfBasisFunctions) mindestens Große 1 besitzen. Dagegen kann die zweite Funktionenmenge

auch leer sein und keine Funktionen enthalten. Diese zweite Menge dient zur Definition gemisch-

ter Finiter Elemente (siehe auch Abschnitt 10.2.3). Intern wird aus diesen Werten bestimmt,

wieviele Mengen an Basisfunktionen verwendet werden.

• ElementType elType bezeichnet einen Enumerationstyp mit moglichen Werten Unit Cuboid, Unit Prism,

Unit Pyramid, Unit Tetrahedron, Unit Interval . Unit Triangle , Unit Quadrangle. Diese beziehen sich auf die

zugehorigen Geometrien der vordefinierten Referenzelemente in den verschiedenen Dimensio-

nen. Fur diese Elemente sind in Klassenspezialisierungen die entsprechenden Gaußpunkte und

-gewichte fur unterschiedliche Genauigkeiten enthalten.

• IntegrationAccuracy intAcc ist ein Enumerationstyp mit Gauss1, Gauss2, Gauss3. Diese Werte entspre-

chen den Integrationsgenauigkeiten auf dem jeweiligen Referenzelement. Dabei werden bei Gauss1

lineare Polynome, bei Gauss2 Polynome vom Grad 3 und bei Gauss3 Polynome vom Grad 5 exakt

integriert. Die Gaußquadraturen liefern des Weiteren gute Approximationen fur Integrale, deren

Integranden keine Polynome sind (siehe Abschnitt 10.1.5).

• typename ETYPE stellt den mathematischen Grunddatentyp der resultierenden Diskretisierungs-

sterne dar. Per Default ist dieses Template auf double gesetzt, kann aber jeden beliebigen Daten-

typ annehmen, fur den die Grundrechenarten, Wurzel (sqrt) und Betrag (fabs bzw. abs) definiert

sind. Diese konnen also auch komplexwertig sein.

• StencilType STENCIL beschreibt einen Enumerationstyp mit den Werten STLVector oder Array. Diese

Werte stehen fur die zugrunde liegende Datenstruktur der resultierenden Diskretisierungssterne,

die entweder aus STL Vektoren oder dynamischen Feldern aufgebaut sein konnen.

• typename eTYPE umfasst einen der fundamentalen Datentypen float oder double und stellt einen

internen Datentypen fur die Datenstrukturen der Gaußpunkte und Koordinaten der Elemente

dar. Dabei ist zu beachten, dass eType ein Datentyp sein muss, der in den Typ ETYPE umgewandelt

werden kann.

• BasisFunctionType BFnType beschreibt einen Enumerationstyp mit den beiden Werten onedimensional

bzw. vectorBasisFunctions . Diese dienen zur Unterscheidung zwischen skalarwertigen Basisfunktio-

nen und den vektorwertigen Kantenelementen, siehe Abschnitt 10.2.4. Denn in diesen Fallen sind

unterschiedliche Berechnungen fur die transformierten Integranden anzuwenden.

Nach dieser Beschreibung der Template-Parameter der Klasse Domain werden nun noch die wichtigen

Methoden zusammengestellt. Diese sind zum Teil in der Klasse selbst definiert, bzw. werden von ei-

ner der funf Funktionsklassen geerbt. Die in den folgenden Ausfuhrungen erwahnten Listen-, Vektor-,

Matrix- bzw. Tensor-Datenstrukturen beschreiben Container, deren Elemente sich uber den Indexope-

rator operator[ ] ansprechen lassen.

• Zur Definition neuer Elemente sind die Basisfunktionen auf dem Referenzelement einzufuhren.

Dazu dient die Funktion Set, die als Argument Ausdrucke vom Typ FunctionExpr erhalt, siehe dazu

129

Page 146: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

Abschnitt 11.4.2. Dabei kann spezifiziert werden, in welche Menge die Funktionen eingetragen

werden, per Default in die erste Funktionenmenge. Zusatzlich sind fur Kantenelemente die Eck-

punkte der Kante anzugeben, auf welcher die Funktion einen Freiheitsgrad beschreibt (mittels

Index in der lokalen Nummerierung auf dem Referenzelement, siehe z.B. Listing 11.5).

template < c l a s s Func t i onExp r e s s i on >

i n l i n e vo id Set ( const Func t i onExp r e s s i on & a ) ;

template < c l a s s Func t i onExp r e s s i on >

i n l i n e vo id Set ( Ba s i s Func t i onSe t setNumber , const Func t i onExp r e s s i on & a ) ;

template < c l a s s Func t i onExp r e s s i on >

i n l i n e vo id Set ( const Func t i onExp r e s s i o n & a ,

uns igned i n t cnr 1 , uns igned i n t cn r 2 ) ;

• Die Koordinaten der Diskretisierungspunkte fur die Bestimmung der Transformation, werden

uber den Klammeroperator an das Finite Element ubergeben. Diese Koordinaten mussen sequen-

tiell als Liste in der Form x0,y0,z0,x1,y1,z1 ,... abgespeichert sein. Intern werden aus diesen Koor-

dinaten die Transformationsformel sowie deren Ableitungen berechnet. Falls fur das Element we-

niger als die mittels des entsprechenden Template-Parameters angegebenen Punkte fur die Trans-

formation benotigt werden, kann dies durch das zweite Argument eingeschrankt werden. Die Me-

thode gibt ein Domain -Objekt zuruck, welches zur Vereinfachung mit DOMAIN WITH TEMPLATES

bezeichnet ist.

template < c l a s s PointArrayTYPE >

i n l i n e DOMAIN WITH TEMPLATES&

ope ra to r ( ) ( const PointArrayTYPE& cc , const i n t numberPoints=corne r sOfE l ement ) ;

• Die numerische Integration der schwachen Formulierung auf einem Finiten Element wird durch die

integrate -Funktionen durchgefuhrt, wobei die ubergebenen Integranden vom Typ BasisFunctionExpr

sein mussen (siehe Abschnitt 11.3). Große und Dimension der Steifigkeitsmatrix berechnen sich

aus den Basisfunktions-Platzhaltern im Integranden.

Fur die Durchfuhrung der Integration (nach der vorgegebenen Genauigkeit) werden zwei Me-

thoden angeboten. Die erste Version hat den resultierenden Diskretisierungsstern als Ruckgabe-

wert, der jedoch aus Effizienzgrunden nicht kopiert, sondern by reference ubergeben wird. Fur

diesen Stern (STENCIL), der aus dem durch StencilType festgelegten Datentyp aufgebaut ist, re-

serviert Colsamm den notigen Speicher. Die zweite Variante speichert den Diskretisierungsstern

in einer benutzerdefinierten Tensor-Datenstruktur, die als Funktionsargument ubergeben wird

(StencilType& stencil ).

template < c l a s s I n t eg r and >

i n l i n e STENCIL& i n t e g r a t e ( const Bas i sFunc t i onExp r < I n t eg r and > & a ) ;

template < typename StenType , c l a s s I n t eg r and >

i n l i n e vo id i n t e g r a t e ( StenType& s t e n c i l , const Bas i sFunct i onExpr <I n teg rand >& a ) ;

• Neben der Integration kann auch eine Auswertung an vorgegebenen Punkten im Element imple-

mentiert werden. Dies wird beispielsweise bei der Berechnung von Dirac-Funktionen benotigt.

Die Große des Ergebnistensors wird dabei wiederum aus den Platzhaltern in der ubergebenen

Funktion bestimmt (Abschnitt 11.3).

template < c l a s s I n t eg r and >

i n l i n e STENCIL TYPE& va l u e ( const Bas i sFunct i onExpr <I n teg rand > & a ) ;

• Um diese Auswertung von Funktionen an beliebigen Stellen im Element zu ermoglichen, konnen

mittels Point die Koordinaten zusatzlicher Punkte an das Element ubergeben werden. Fur diese

130

Page 147: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

werden dann intern alle notigen Berechnungen durchgefuhrt. Die Funktion Point Test testet nach

dem Setzen zusatzlich, ob er Punkt innerhalb des aktuellen Elements liegt.

template < c l a s s PointArrayTYPE >

vo id Po i n t ( const PointArrayTYPE & po i n t ) ;

template < c l a s s PointArrayTYPE >

boo l Po i n t Te s t ( const PointArrayTYPE & po i n t ) ;

• Zuletzt werden noch einige Methoden zusammengefasst, die Informationen uber die gesetzten

Template-Paramater liefern. Die folgenden Funktionen geben die Großen der entsprechenden

Basisfunktionenmengen zuruck.

uns igned i n t s i z e S e t 1 ( ) const ;

uns igned i n t s i z e S e t 2 ( ) const ;

Des Weiteren eine Methode zur Bestimmung der Anzahl der definierten Diskretisierungspunkte.

uns igned i n t getNumberCorners ( ) const ;

Schließlich eine Funktion, welche die Dimension des Elements zuruckgibt.

uns igned i n t d imens i on ( ) const ;

Nachfolgend werden die Eigenschaften der funf Funktionsklassen kurz zusammengefasst, ohne dabei

genauer auf deren Realisierung einzugehen.

B.2.2 Gaussian Points

Fur die Anwendung der Gauß’schen Quadraturformel werden je nach Integrationsgenauigkeit und Geo-

metrie des Referenzelements die entsprechenden Stutzstellen und Gewichte benotigt [SB02]. Da die ver-

schiedenen Integrationsstufen der einzelnen Elemente anhand der Template-Parameter unterscheidbar

sind, sind fur jede notige Kombination spezialisierte Versionen der Klasse Gaussian Points implemen-

tiert. Diese beinhalten dann bereits die entsprechenden Stutzstellen und Gewichte. Daruber hinaus ist

konnen diese bereits implementierten Klassen einfach durch zusatzliche Spezialisierungen auf weitere

Integrationsgenauigkeiten und -gebiete erweitert werden.

B.2.3 Basis Function

Fur die FE-Diskretisierungen sind Freiheitsgrade zu definieren. Die Lage dieser Freiheitsgrade kann

dabei durch die Formeln der Basisfunktionen auf dem Referenzelement festgelegt werden. Die Basis-

funktionen, die mit der Methode Set gesetzt werden, werden intern mittels abstrakter Klasse (Abschnitt

7.3) abgespeichert. Die Performance dieser Implementierung ist zwar nicht optimal, doch werden die

Basisfunktion lediglich einmalig bei der Initialisierung des Objektes an den Gaußpunkten ausgewertet,

so dass dies kaum ins Gewicht fallt. Die berechneten Werte der Basisfunktionen und deren Ableitungen

an den Gaußpunkten im Referenzelement werden intern abgespeichert. Da es sich hierbei nur um rela-

tiv geringe Datenmengen handelt, auf die schnell und oft zugegriffen werden muss, werden die Daten

in Feldern (auf dem Stack) angelegt.

B.2.4 Mapping

Die Template-Klasse Mapping dient zur Berechnung und Speicherung der Werte der Transformation,

deren Ableitungen sowie der Determinante bzw. Lange der Normalen an den Gaußpunkten. Je nach

Dimension des Finiten Elements sind fur die Durchfuhrung der Kettenregel und Bestimmung der

131

Page 148: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

Inversen der Jacobi-Matrix unterschiedliche Formeln anzuwenden. Gleiches gilt auch fur die Vorbe-

rechnungen der Jacobi-Determinante bzw. der Lange des Normalenvektors, wobei die Unterscheidung

zwischen Berechnungen im Inneren oder am Rand. Da diese Berechnungen fur regulare Anwendungen

haufig durchgefuhrt werden mussen (einmal pro Element), wurde hierzu die schnelle Auswertung uber

FET gewahlt (Abschnitt 6.2).

Auch hier konnen durch Spezialisierungen weitere Abbildungsklassen definiert werden, beispielsweise

auch fur vierdimensionale Berechnungen.

B.2.5 CornerClasses

Die Klasse CornerClasses stellt den Speicher fur die Koordinaten der Finiten Elemente bereit. Dies

konnen, z.B. bei isoparametrischen Elementen, mehr sein als die Eckenzahl der zugrunde liegenden

Referenzgeometrie, da durch die entsprechende Transformation Zwischenpunkte auf die Kanten des

Referenzelements abgebildet werden.

B.2.6 StencilTypeInit

Je nach Problemstellung der PDG auf dem Finiten Element entstehen null- bis dreidimensionale lokale

Diskrestisierungssterne. Diese Dimension hangt dabei von den (Differential-)Operatoren der schwachen

Formulierung der PDG ab, und die Große der in der jeweiligen Dimension von der Anzahl der Basisfunk-

tionen, siehe auch Abschnitt 11.4.2. Daruber hinaus ist der implementierte Mechanismus auf weitere

Datentypen erweiterbar. Dazu sind lediglich eine weitere Spezialisierungen der StencilyTypeInit -Klasse

fur entsprechende Datentypen einzufuhren.

B.2.7 Simple Element, Mixed Element, Vectorial Element

Zur Definition von speziellen Finiten Elementen muss eine entsprechende Element-Klasse definiert

werden, welche

1. von der Klasse Domain mit entsprechenden Template-Parametern erbt, und

2. einen Default-Konstruktor definiert, welcher die Definitionen der Basisfunktionen auf dem Refe-

renzelement vornimmt.

Damit nicht fur jede Definition alle Parameter angegeben werden mussen, existieren sog. Zwischen-

elemente, welche bereits einen Teil der Template-Parameter setzen. Neu eingefuhrte Elemente konnen

dann wiederum von diesen Zwischenelementen erben, und erhalten so die volle Funktionalitat der

Klasse Domain . Falls dennoch Elemente definiert werden sollen, die mit den Zwischenelementen nicht

beschreibbar sind, so konnen weiterhin eigene Ableitungen von Domain eingefuhrt werden. Zusatz-

lich dienen wie vorher die Default-Template-Parameter dazu, dass nur die elementspezifischen Daten

gesetzt werden mussen, sofern die Default-Werte fur die Anwendung passen.

• Die Klasse Simple Element dient zur Definition von inneren Finiten Elementen mit nur einer Menge

von reellwertigen Ansatz- bzw. Testfunktionen. Entsprechend muss hierbei nur noch die Große

einer Funktionenmenge angegeben werden, die zweite wird intern auf null gesetzt.

template< i n t numberCorners , DIMENSION dim ,

c l a s s TRAFO, i n t numberOfFunctions ,

ElementType elType , I n t e g r a t i o nA c c u r a c y i n tAcc = Gauss2 ,

typename ETYPE = double , s t e n c i l T y p e STENCIL = STLVector ,

typename eTYPE = double >

c l a s s S imp l e E l ement ;

132

Page 149: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

• Analog dazu beschreibt die Klasse Simple Boundary Element die Template-Parameter fur Randele-

mente mit nur eine Menge von Basisfunktionen. Auch hier wird die Große der zweiten Menge

intern auf null gesetzt.

template< i n t numberCorners , DIMENSION dim ,

c l a s s TRAFO, i n t numberOfFunct ions ,

ElementType elType , I n t e g r a t i o nA c c u r a c y i n tAcc = Gauss2 ,

typename ETYPE = double , s t e n c i l T y p e STENCIL = STLVector ,

typename eTYPE = double >

c l a s s S imp l e Bounda ry E l ement ;

• Fur gemischte Finite Elemente Ansatze dient die Klasse Mixed Element. Hierbei werden die Großen

von zwei Mengen von Basisfunktionen definiert. Dieses Zwischenelement ist noch nicht als inneres

oder Randelement festgelegt.

template< i n t numberCorners , DIMENSION dim ,

c l a s s TRAFO, i n t numberOfFunct ions ,

i n t numberOfFunctions2 , ElementType elType ,

I n t e g r a t i o nA c c u r a c y i n tAcc = Gauss2 ,

d oma i nSp e c i f i c a t i o n i n t e r i o r I b o u n d a r y ,

typename ETYPE = double , s t e n c i l T y p e STENCIL = STLVector ,

typename eTYPE = double >

c l a s s Mixed Element ;

• Als letztes Zwischenelement dient die Klasse Vectorial Element zur einfacheren Definition von vek-

torwertigen Finiten Elementen, siehe Abschnitt 10.2.4. Hierbei ist ebenfalls nur eine Menge von

Basisfunktionen einzufuhren.

template< i n t numberCorners , DIMENSION dim , c l a s s TRAFO,

i n t numberOfFunct ions , ElementType elType ,

I n t e g r a t i o nA c c u r a c y i n tAcc = Gauss2 ,

d oma i nSp e c i f i c a t i o n i n t e r i o r I b o u n d a r y ,

typename ETYPE = double , s t e n c i l T y p e STENCIL = STLVector ,

typename eTYPE = double >

c l a s s Ve c t o r i a l E l emen t ;

Alle in Colsamm vordefinierten Finiten Elemente wurden mit diesem Mechanismus als (indirekte)

Ableitung der Klasse Domain realisiert.

133

Page 150: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG B. COLSAMM – PROGRAMMSTRUKTUR

134

Page 151: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG C. PROGRAMMIERUNG VON TYPLISTEN

C Programmierung von Typlisten

Type lists (Typlisten) dienen zur Speicherung von Typen in Listen. Die nachfolgenden Implemen-

tierungen mit Template-Spezialisierungen und Traits basieren auf den Prinzipien der funktionalen

Programmierung [Ale01].

Eine Typliste (Typelist ) besteht aus dem Kopf und dem Rest der Listet. Der Kopf beschreibt dabei

das gespeicherte Element (einen Datentyp) und der Rest ist entweder wieder eine Typliste oder ein

NullType. Mit dem Makro TPYELIST wird eine Typliste aus einem Element generiert.

template <c l a s s H, c l a s s T>

s t r u c t T yp e l i s t

t ypede f H Head ;

t ypede f U Ta i l ;

;

c l a s s Nul lType ;

#d e f i n e TYPELIST (ENTRY) Type l i s t <ENTRY, Nul lType>

Zur Bestimmung der Lange einer Typliste wird die Liste rekursiv uber die Typen bis zum abschlie-

ßenden NullType durchlaufen. Fur jeden Eintrag der Typliste wird 1 addiert.

template <c l a s s TList>

s t r u c t Length ;

template <>

s t r u c t Length<Nul lType >

enum v a l u e = 0 ;

;

template <c l a s s H, c l a s s T>

s t r u c t Length<Type l i s t <H,T> >

enum v a l u e = 1 + Length<T> : : v a l u e ;

;

Um einen neuen Typ an eine bestehende Typliste anzuhangen, wird durch die Liste bis zum NullType

gelaufen und dann ein neuer Eintrag generiert. Ist der neue Eintrag selbst der NullType, so wird nichts

eingetragen.

template <c l a s s TList , c l a s s ENTRY>

s t r u c t Append ;

template <>

s t r u c t Append<Nul lType , Nul lType>

t ypede f Nul lType LIST ;

;

template <c l a s s ENTRY>

s t r u c t Append<Nul lType ,ENTRY>

t ypede f TYPELIST (ENTRY) LIST ;

;

template <c l a s s Head , c l a s s Ta i l >

s t r u c t Append<Nul lType , Type l i s t <Head , Ta i l> >

t ypede f Type l i s t <Head , Ta i l> LIST ;

;

template <c l a s s Head , c l a s s Ta i l , c l a s s ENTRY>

s t r u c t Append<Type l i s t <Head , Ta i l >,ENTRY>

t ypede f Type l i s t <Head , typename Append<Ta i l ,ENTRY> : : LIST> LIST ;

;

135

Page 152: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG C. PROGRAMMIERUNG VON TYPLISTEN

Beim Verschmelzen zweier Typlisten werden die Elemente der ersten Liste sukzessive in die zweite

Liste eingetragen.

template <c l a s s TList1 , c l a s s T l i s t 2 >

s t r u c t Jo in ;

template <>

s t r u c t Jo in<Nul lType , Nul lType >

t ypede f Nul lType LIST ;

;

template <c l a s s T>

s t r u c t Jo in<Nul lType ,T>

t ypede f T LIST ;

;

template <c l a s s Head , c l a s s Ta i l , c l a s s TList2>

s t r u c t Jo in<Type l i s t <Head , Ta i l >, TLi s t2 >

t ypede f typename Jo in<Ta i l ,

typename Append<TList2 , Head > : : LIST > : : LIST LIST ;

;

Soll eine Eintrag bei seinem ersten Auftreten in der Liste geloscht werden, so wird solange durch die

Liste gelaufen, bis der Kopf der aktuellen Teilliste mit dem zu loschenden Eintrag ubereinstimmt.

template <c l a s s TList , c l a s s ENTRY>

s t r u c t Era se ;

template <c l a s s ENTRY>

s t r u c t Erase<Nul lType ,ENTRY>

t ypede f Nul lType LIST ;

;

template <c l a s s ENTRY, c l a s s Ta i l>

s t r u c t Erase<Type l i s t <ENTRY, Ta i l >,ENTRY>

t ypede f Ta i l LIST ;

;

template <c l a s s Head , c l a s s Ta i l , c l a s s ENTRY>

s t r u c t Erase<Type l i s t <Head , Ta i l >,ENTRY>

t ypede f Type l i s t <Head ,

typename Erase<Ta i l ,ENTRY> : : LIST> LIST ;

;

Zum Erstellen einer Liste ohne Duplikate wird rekursiv eine Liste ohne Duplikate erzeugt, indem

der Kopf der aktuellen Teilliste aus dem Rest geloscht wird. Dieser ist selbst bereits eine Liste ohne

Duplikate, so dass ein Loschen beim ersten Auftreten genugt.

template <c l a s s TList>

s t r u c t NoDup l i ca te s ;

template <>

s t r u c t NoDupl i cates <Nul lType >

t ypede f Nul lType LIST ;

;

template <c l a s s Head , c l a s s Ta i l>

s t r u c t NoDupl i cates <Type l i s t <Head , Ta i l > >

p r i v a t e :

t ypede f typename NoDupl i cates <Ta i l > : : LIST L1 ;

t ypede f typename Erase<L1 , Head > : : LIST L2 ;

pub l i c :

t ypede f Type l i s t <Head , L2> LIST ;

;

Zum Abschluss wird noch die Klasse CountVariables definiert, die in Abschnitt 12.3 verwendet wird,

um die Anzahl an verschiedenen nummerierten Vektoren zu bestimmen. Da bei den Variablen, die

im Cache gehalten werden sollen auch der Ergebnisvektor berucksichtigt werden muss, wird dieser

zunachst der Typliste des Ausdrucks hinzugefugt. Aus der resultierenden Typliste werden anschließend

alle Duplikate entfernt. Der Enumerationswert value enthalt dann die Lange der so erstellten Typliste.

136

Page 153: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG C. PROGRAMMIERUNG VON TYPLISTEN

template <c l a s s A, c l a s s B>

s t r u c t Coun tVa r i a b l e s

t ypede f typename NoDupl i cates <

typename Jo in<typename A : : VARIABLE LIST ,

typename B : : VARIABLE LIST > : : LIST > : : LIST

RESULT ;

enum v a l u e = Length<RESULT> : : v a l u e ;

;

137

Page 154: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG C. PROGRAMMIERUNG VON TYPLISTEN

138

Page 155: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG D. VERWENDETE COMPUTER-PLATTFORMEN

D Verwendete Computer-Plattformen

D.1 Arbeitsplatzrechner

Auf den nachfolgend aufgefuhrten Worstations wurde mit unterschiedlichen Versionen des GNU-C++-

Compilers gerarbeitet (Versionen 3.3.2 bis 4.1.0).

D.1.1 Pentium 4

• CPU: 3.0 GHz, P4, Hyperthreading

• Peak-Performance: mittels SSE2 6 GFlops

• Cache: L2 512 kB

• RAM: 2 GByte

D.1.2 Dual-Core

• CPU: 2 x Intel(R) Core(TM)2 CPU 6600, 2.40GHz

• Peak-Performance: mind. 4.8 GFlops pro Kern, also insgesamt 9.6 GFlops

• Cache: L2 4 MB

• RAM: 4 GByte

D.2 Hochleistungsrechner

D.2.1 NEC SX-6/48M6

Die NEC SX-6/48M6 ist eine shared memory Vektorplattform. Die Berechnungen wurden mittels au-

tomatischer Vektorisierung auf einem Knoten durchgefuhrt [HLR05].

• Hochstleistungsrechenzentrum Stuttgart (HLRS)

• 6 Knoten mit je 8 CPUs, je 565 MHz

• Peak-Performance: 9 GFlops auf einem Knoten mit 8 CPUs (da Addition und Multipliktion in

einem Takt)

• RAM: 16 GB pro CPU

• Compiler: sc++ von NEC

139

Page 156: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG D. VERWENDETE COMPUTER-PLATTFORMEN

D.2.2 Hitachi SR8000-F1/168

Die Maschine bestand aus 168 Pseudo-Vektor-Knoten, die wiederum aus je acht effektiv nutzbaren

CPUs bestanden [Hit98]. Auf jedem Knoten konnten Gleitpunktoperationen auf den acht Prozessoren

parallel abgearbeitet werden (SIMD).

• LRZ Garching, 2006 stillgelegt

• 168 Knoten mit je 8 CPUs, je 375 Mhz

• Peak-Performance: 12 GFlops auf einem Knoten mit 8 CPUs

• RAM: 8 GB pro Knoten

• Compiler: sCC von Hitachi

D.2.3 Cluster

Der AMD-Opteron-Cluster am Lehrstuhl Informatik 10, Erlangen besteht aus 9 Dual- und 8 Quad-

Knoten [Dep05]. Alle Knoten sind mit einer GBit-Schnittstelle verbunden, die Vierfachknoten zusatz-

lich mit Infiniband. Dieses ermoglicht eine Ubertragungsbandbreite von 10 GBit/s.

Dual- bzw. Quad-Knoten:

• 2 bzw. 4 Rechenkerne

• CPU: 2.2 GHz AMD Opteron 248

• Peak-Performance: mittels 1 MultAdd/Takt = 2 Flops/Takt = 4.4 GFlops folgen insgesamt 17.6

GFlops

• Cache: L2 1 MB

• RAM: DDR 333, 4 GB fur Dual-Knoten, 16 GB fur Quad-Knoten yte

• Compiler: GNU-Compiler, Versionen 3.3.3, 4.0.1 bzw. 4.1.0, sowie Intel-C++-Compiler, Versionen

8.1 und 9.0

140

Page 157: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG E. CURRICULUM VITAE

E Curriculum Vitae

Jochen Hardtlein

03. August 2007

Allgemeine Informationen

Geburtstag: 22. Februar 1977

Geburtsort: Rothenburg ob der Tauber

Familienstand: ledig

Anschrift: Wildbadweg 1, Steinach / Ens

D–91605 Gallmersgarten

Email: [email protected]

WWW: www10.informatik.uni–erlangen.de/∼jochen

Ausbildung

Juli 2003–Marz 2007 Doktorand am Lehrstuhl Informatik 10,

Systemsimulation, Universitat Erlangen-Nurnberg

Nov. 2002–Juni 2003 Doktorand am Lehrstuhl fur Angewandte

Mathematik II, Universitat Wurzburg

Nov. 1997–Okt. 2002 Mathematik-Studium an der Universitat Wurzburg,

Nebenfach: Informatik, Abschluss: Diplom–Mathematiker

Aug. 1996–Okt. 1997 Ersatzdienst im Evang. Jugendheim in Rothenburg o.d.T

Sep. 1987–Juli 1996 Gymnasium Rothenburg ob der Tauber

Abschluss Allgemeine Hochschulreife (Abitur)

Anstellungsverhaltnisse

Nov. 2005– Jan 2006 Forschungsaufenthalt am Lawrence Livermore

National Laboratory, Kalifornien USA.

Juli 2003– Marz 2007 Wissenschaftl. Angestellter am Lehrstuhl Informatik 10,

Systemsimulation, Universitat Erlangen–Nurnberg

Nov. 2002–Juni 2003 Wissentschaftl. Angestellter am Institut fur

Angewandte Mathematik II, Universitat Wurzburg

141

Page 158: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

ANHANG E. CURRICULUM VITAE

142

Page 159: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

EIGENE VEROFFENTLICHUNGEN

Eigene Veroffentlichungen

[HLP05] J. Hardtlein, A. Linke und C. Pflaum. Fast Expression Templates. Computational Science

- ICCS 2005, Vol. 3515 LNCS, Seiten 1055 1063. Springer-Verlag, 2005.

[HLP06a] J. Hardtlein, A. Linke und C. Pflaum. Blocking Techniques with Fast Expression Tem-

plates . Technischer Bericht 06-0, Lehrstuhl fur Informatik 10, Systemsimulation, Uni-

versitat Erlangen-Nurnberg, 2006.

[HLP06b] J. Hardtlein, A. Linke und C. Pflaum. Fast Expression Templates - Enhancements for

High Performance C++ Libraries. Technischer Bericht 06-7, Lehrstuhl fur Informatik

10, Systemsimulation, Universitat Erlangen-Nurnberg, 2006.

[HLPW06] J. Hardtlein, A. Linke, C. Pflaum und C. H. Wolters. Advanced Expression Templates

Programming. Computing and Visualization in Science, Springer-Verlag, 2006. Einge-

reicht 2006, derzeit in Begutachtung.

[HP05] J. Hardtlein und C. Pflaum. Efficient and User-friendly Computation of Local Stiffness

Matrices. Frontiers in Simulation, Simulationstechnique, 18. Symposium in Erlangen,

2005.

[QVP+06] D. Quinlan, R. Vuduc, T. Panas, J. Hardtlein und A. Saebjoernsen. Support for Whole-

Program Analysis and the Verification of the One-Definition Rule in C++. NIST Special

Publication 500-262, Proceedings von Static Analysis Summit. Gaithersburg, MD, 2006.

[WKM+06a] C.H. Wolters, H. Kostler, C. Moller, J. Hardtlein und A. Anwander. Numerical Approa-

ches for Dipole Modeling in Finite Element Method based Source Analysis. Cheyne, D.,

Ross B., Stroink G., und Weinberg, H.(eds.), International Congress Series 1300, 2006.

in press.

[WKM+06b] C.H. Wolters, H. Kostler, C. Moller, J. Hardtlein, L. Grasedyck und W. Hackbusch.

Numerical mathematics of the subtraction method for the modeling of a current dipole in

EEG source reconstruction using finite element head models. SIAM Journal on Scientific

Computing, 2006. Eingereicht 2006, derzeit in Begutachtung.

143

Page 160: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

EIGENE VEROFFENTLICHUNGEN

144

Page 161: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

LITERATURVERZEICHNIS

Literaturverzeichnis

[AELS99] L. Alvarez, J. Escların, M. Lefebure und J. Sanchez. A PDE model for computing the optical

flow. Proc. XVI Congreso de Ecuaciones Diferenciales y Aplicaciones, pages 1349–1356, Las

Palmas de Gran Canaria, Spain, 1999.

[AG05] A. Abrahams und A. Gurtovoy. C++ Template Metaprogramming, Concepts, Tools, and

Techniques from Boost and Beyond. Addison-Wesley, 2005.

[Ale01] A. Alexandrescu. Modern C++ Design, Generic Programming and Design Patterns Applied.

Addison-Wesley, 2001.

[AS01] D. Abrahams und J. G. Siek. Policy Adaptors and the Boost Iterator Adaptor Library.

Second Workshop on C++ Template Programming, October 2001.

[ASU86] A.V. Aho, R. Sethi und J. D. Ullman. Compilers: Princiles, Techniques, and Tools. Addison-

Wesley, 1986.

[BCHQ97] D. Brown, G. Chesshire, W. Henshaw und D. Quinlan. OVERTURE: An Object-Oriented

Software System for Solving Partial Differential Equations in Serial and Parallel Environ-

ments, 1997. Eight SIAM Conference on Parallel Processing for Scientific Computing, Min-

neapolis, Minnesota.

[BDQ97] F. Basetti, K. Davis und D. Quinlan. C++ Expression Templates Performance Issues in

Scientific Computing, Oct 1997. CRPC-TR97705-S.

[BF01] R.L. Burden und J.D. Faires. Numerical Analysis. Brooks/Cole, seventh edition, 2001. 2

copies.

[Bra97] D. Braess. Finite Elements: Theory, Fast Solvers, and Applications in Solid Mechanics.

Cambridge University Press, second edition, 1997.

[Bru06] A. Bruhn. Variational Optic Flow Computation: Accurate Modeling and Efficient Nume-

rics. PhD thesis, Department of Mathematics and Computer Science, Saarland University,

Saarbrucken, 2006.

[BS94] S.C. Brenner und L. R. Scott. The Mathematical Theory of Finite Element Methods. Num-

ber 15 in Texts in Applied Mathematics. Springer, 1994.

[CBHR] C.Freundl, B. Bergen, F. Hulsemann und U. Rude. Parexpde: Expression templates and

advanced pde software design on the hitachi sr8000. In A. Bode und F. Durst, editors,

High Performance COmputing in Science and Engineering, Garching 2004. Springer. ISBN

3-540-26145-1.

[CDK+01] R. Chandra, L. Dagum, D. Kohr, D. Maydan, J. McDonald und R. Menon. Parallel Pro-

gramming in OpenMP. Academic Press, 2001.

[Cia02] P.G. Ciarlet. The Finite Element Method for Elliptic Problems. SIAM, 2002.

145

Page 162: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

LITERATURVERZEICHNIS

[CL93] B. Cabral und L.C. Leedom. Imaging vector fields using line integral convolution. SIGGRAPH

’93: Proceedings of the 20th annual conference on Computer graphics and interactive techni-

ques, pages 263–270, New York, NY, USA, 1993. ACM Press.

[CSvS86] C. Cuvelier, A. Segal und A.A. van Steenhoven. Finite Element Methods and Navier-Stokes

Equations. D. Reidel Publishing Company, 1986.

[DA03] B. Dawes und D. Abrahams. BOOST , 2003. http://www.boost.org.

[Dep05] Department of Computer Science 10, System Simulation, Erlangen. HPC Cluster, 2005.

http://www10.informatik.uni-erlangen.de/Cluster/hpc.shtml.

[DJ03] Vandevoorde D und N.M. Josuttis. C++ Templates - The Complete Guide. Addison-Wesley,

2003. ISBN 0-201-73484-2.

[EV01] R. Eigenmann und M.J. Voss. OpenMP Shared Memory Parallel Programming, 2001. Lecture

Notes in Computer Science 2104 (Heidelberg: Springer-Verlag).

[Fra05] Fraunhofer IIS-B Erlangen. ORCAN - Open Reflective Component Architecture, 2005.

http://sourceforge.net/projects/orcan.

[Fur97] G. Furnish. Disambiguated Glommable Expression Templates. Computers in Physics, volume

11, No. 3, pages 263–269, May/June 1997.

[GG] J. Gil und Z. Gutterman. Compile Time Symbolic Derivation with C++ Templates. pages

249–262.

[GR05] C. Großmann und H. Roos. Numerische Behandlung partieller Differentialgleichungen. Teub-

ner, 2005.

[Han96] S. Haney. Beating the Abstraction Penalty in C++ Using Expression Templates. In P. Du-

bois, editor, Computers in Physics, volume 10, No. 6, pages 552–557. American Institute Of

Physics, Nov/Dec 1996.

[HCKS98] S. Haney, J. Crotinger, S. Karmesin und S. Smith. PETE: The Portable Expression Tem-

plates Engine, 1998. Dr. Dobb’s Journal of Software Tools, 24(10):88, pages 90–92, 94–95.

[Hen02] W. Henshaw. OVERTURE: An Object-Oriented Framework for Overlapping Grid Applicati-

ons, 2002. UCRL-JC-147889, Paper for the 2002 AIAA conference on Applied Aerodynamics,

St Louis, MO.

[Heu98] H. Heuser. Lehrbuch der Analysis - Teil 2 . Teubner, 1998.

[Hit98] Hitachi Ltd. The Hitachi SR8000 Series Super Technical Server, Homepage, 1998.

http://www.hitachi.co.jp/Prod/comp/hpc/eng/sr81e.html.

[HLR05] HLRS – High Performance Center Stuttgart. The NEC SX-6 Cluster Documentation, 2005.

http://www.hlrs.de/hw-access/platforms/sx6/user doc.

[HS81] B.K.P Horn und B.G. Schunck. Determining optical flow. Artificial Intelligence, (17):185–203,

1981.

[Jin02] Jianmingg Jin. The Finite Element Method in Electromagnetics – Second Edition. IEEE-

Press, Wiley-Interscience Publication, 2002.

[JL01] M. Jung und U. Langer. Methode der finiten Elemente fur Ingenieure. B.G. Teubner, 2001.

146

Page 163: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

LITERATURVERZEICHNIS

[KA00] P. Knabner und L. Angermann. Numerik partieller Differentialgleichungen. Springer-Verlag,

2000.

[Koo03] Kooperation der Max-Plank Institute Leipzig/Munchen, Institut fur Biomagnetismus und

Biosignalanalyse Munster. NeuroFEM - A finite element software fast computation of the

forward solution in EEG/MEG source localisation, 2003. http://www.neurofem.com/.

[Kow04] M. Kowarschik. Data Locality Optimizations for Iterative Numerical Algorithms and Cellular

Automata on Hierarchical Memory Architectures. PhD thesis, Lehrstuhl fur Informatik 10

(Systemsimulation), Institut fur Informatik, Universitat Erlangen-Nurnberg, July 2004. SCS

Publishing House, ISBN 3-936150-39-7.

[Lan02] H. P. Langtangen. Computational Partial Differential Equations – Numerical Methods and

Diffpack Programming. Springer, 2002.

[LHKK79] C. L. Lawson, R. J. Hanson, D. R. Kincaid und F. T. Krogh. Algorithm 539: Basic Li-

near Algebra Subprograms for Fortran Usage [F1]. 5(3):324–325, September 1979. ACM

Transactions on Mathematical Software.

[LP03] A. Linke und C. Pflaum. Fast Expression Templates for the SR 8000 Supercomputer. 2003.

Proceedings of the Workshop on Parallel/High-Performance Object-Oriented Scientific Com-

puting (POOSC).

[LvG99] M. Lerch und J. Wolff von Gudenberg. Expression Templates for Dot Product Expressions.

5:69–80, 1999. Reliable Computing.

[Mas01] I. Masakatsu. MET – Matrix Expression Templates Homepage, 2001.

http://met.sourceforge.net.

[McP04] S. McPeak. Elsa: An Elkhound-based C++ Parser, 2004.

http://www.cs.berkeley.edu/ smcpeak/elkhound/sources/elsa/index.html.

[MN04] S. McPeak und G. Necula. Elkhound: A Fast, Practical GLR Parser Generator, 2004. Pro-

ceedings of Conference on Compiler Constructor (CC04).

[Mon03] P. Monk. Finite Element Methods for Maxwell’s Equations. Nmerical Mathematics and

Scientific Computation. Oxford Science Publications, 2003.

[MS99] M.Gnewuch und S.A.Sauter. Boundary integral equations for second orer elliptic boundary

value problems, 1999. Preprint No. 55, Max-Planck-Institut fur Mathematik in den Natur-

wissenschaften Leipzig.

[MS00] M. Muller und S. Schwarzer. Einfuhrung in C++, 2000. http://www.ica1.uni-

stuttgart.de/Courses and Lectures/C++/script/node24.html.

[Nag83] H.-H. Nagel. Constraints for the estimation of displacement vector fields from image se-

quences. Proc. Eighth International Joint Conference on Artificial Intelligence, volume 2,

pages 945–951, Karlsruhe, West Germany, 1983.

[Pet03] O. Petzold. Tiny Vector Matrix library using Expression Templates (TVMET), 2003.

http://tvmet.sourceforge.net.

[Pfl01] C. Pflaum. Expression Templates for Partial Differential Equations, 2001. Comput Visual

Sci 4, 1–8.

[PH67] R. Plonsey und D. Heppner. Considerations on Quasi-Stationarity in Electro-physiological

Systems, 1967. Bull.math.Biophys., 29, pp. 657–664.

147

Page 164: Moderne Expression Templates Programmierung ... · Moderne Expression Templates Programmierung – Weiterentwickelte Techniken und deren Einsatz zur L¨osung partieller Differentialgleichungen

LITERATURVERZEICHNIS

[Qui02] D. Quinlan. ROSE Project Semantic-Based Optimization. 2002. Math Inform. & Computer

Sci. Principle Investigator’s Mtg., Argonne National Labs, June 26.

[Rum96] B. Rumpe. A Formal Methodolgy for the Design of Distributed Object-Oriented Systems.

POOMA’96: Parallel Object-Oriented Methods and Applications, Santa Fe, 1996.

[SB02] J. Stoer und R. Bulirsch. Introduction to Numerical Analysis. Springer, third edition, 2002.

[SK97] H. Shen und D.L. Kao. UFLIC: a line integral convolution algorithm for visualizing unsteady

flows. IEEE Visualization, pages 317–322, 1997.

[SK98] Han-Wei Shen und David L. Kao. A new line integral convolution algorithm for visuali-

zing time-varying flow fields. IEEE Transactions on Visualization and Computer Graphics,

4(2):98–108, 1998.

[SL01] J. Siek und A. Lumsdaine. The Matrix Template Library, 2001. Homepage:

http://www.osl.iu.edu/research/mtl.

[SS00] J. Striegnitz und S. Smith. An Expression Template aware Lambda Function. First Workshop

on C++ Template Programming, Erfurt, Germany, 10 2000.

[SS04] A. Schmidt und K. Siebert. Design of Adaptive Finite Element Software – Thte Finite

Element Toolbox ALBERTA. Springer, 2004.

[Str00] B. Stroustrup. The C++ Programming Language. AT&T, 2000.

[THR05] J. Treibig, S. Hausmann und U. Rude. Performance Analysis of the Lattice Boltzmann

Method on x-86-64 Architectures. In F. Hulsemann, M. Kowarschik und U. Rude, editors,

18th Symposium Simulationstechnique ASIM 2005 Proceedings, volume 15 of Frontiers in

Simulation, pages 736–741. ASIM, SCS Publishing House, Sep 2005.

[TOS01] U. Trottenberg, C. Oosterlee und A. Schuller. Multigrid. Academic Press, 2001.

[Vel95] T. Veldhuizen. Expression Templates, 1995. C++ Report 7 (5), 26–31.

[Vel97] T. Veldhuizen. Will C++ be faster than Fortran?, 1997. Proceedings of the 1st International

Scientific Computing in Object-Oriented Parallel Environments (ISCOPE’97).

[Vel98] T. Veldhuizen. Expression Templates, 1998. Codebeispiele zu Expression Templates, Webpage

http://osl.iu.edu/∼tveldhui/papers/Expression-Templates/exprtmpl.html.

[Vel01] T. Veldhuizen. Blitz++ - Object Oriented Scientific Computing, Homepage, 2001.

http://oonumerics.org/blitz.

[VJ03] D. Vandevoorde und N. Josuttis. C++ Templates - The Complete Guide. Addison-Wesley,

2003.

[VS06] M. Volter und T. Stahl. Model-Driven Software Development : Technology, Engineering,

Management. John Wiley & Sons, June 2006.

[WK02] J. Walter und M. Koch. uBLAS, Boost C++ Libraries - Basic Linear Algebra, 2002.

http://www.boost.org/libs/numeric/ublas/doc/index.htm.

[ZT00a] O.C. Zienkiewicz und R.L. Taylor. The Finite Element Method, Vol. 1: The Basis. Butter-

worth Heinemann, 2000.

[ZT00b] O.C. Zienkiewicz und R.L. Taylor. The Finite Element Method, Vol. 2: Solid Mechanics.

Butterworth Heinemann, 2000.

148