Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R....

22
Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1 , M. Wallace 2 , R. Borgo 1 , & C. Runciman 2 1 Visualization and Virtual Reality Group, University of Leeds, UK 2 Programming Languages and Systems Group, University of York, UK

Transcript of Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R....

Page 1: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

Fine-grained Visualization Pipelines

and Lazy Functional Languages

D.J. Duke1, M. Wallace2, R. Borgo1, & C. Runciman2

1Visualization and Virtual Reality Group, University of Leeds, UK

2Programming Languages and Systems Group, University of York, UK

Page 2: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

2

Overview

Motivation

• why are we doing functional programming?

• a lazy polytypic grid

• Haskell 101

Marching cubes

Functional approaches

• array-based

• streaming

Evaluation

• performance

• software engineering

Outlook

Page 3: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

3

Why (pure) functional programming?

Practical concern: grid-enabled visualization

• new technologies for generic programming (polytypism)

• staged computation

• laziness – natural demand-driven evaluation and streaming

• migration to parallel evaluation

Theoretical concern: abstractions for software development

• problem decomposition program composition

• J. Hughes, Why Functional Programming Matters

• correctness – mathematically tractable, concise

• different way of thinking about problems

Page 4: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

4

What is (pure) functional programming?

Page 5: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

5

Type declaration - optionalHigher-order:

map takes another function

as parameter

Function body:

list of equations

Curried functions:

a -> b -> c rather than (a,b) -> c

makes partial application easy

e.g. (+1), or map (+4)

What is (pure) functional programming?

Functions are first-class citizens

• passed as parameters and/or returned as results

• higher-order functions implement patterns of computation

Expressive type systems

Laziness

Example

map :: (a -> b) -> [a] -> [b]map f [] = []map f (a:as) = (f a) : (map f as)

Pattern matching:

case analysis of list constructor

Laziness:

(f a) etc only evaluated as needed

Type variables:

this function works for any

choice of types “a” and “b”

Page 6: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

6

Haskell 101

Other useful higher-order functions

(.) :: (b -> c) -> (a -> b) -> (a -> c)

(f . g) x = f (g x)

zipWith2 :: (a->b->c) -> [a] -> [b] -> [c]

zipWith2 f [] _ = []

zipWith2 f _ [] = []

zipWith2 f (a:as) (b:bs) = (f a b):(zipWith f as bs)

($) :: (a -> b) -> a -> b

f $ x = f x [Why? Write f . g $ x instead of (f . g) x]

Local definitionslargest :: [a] -> a

largest (a:as) = largest1 a as

where largest1 a [] = a

largest1 a (b:bs) | a > b = largest1 a bs

| otherwise = largest1 b bs

Type classeslargest :: (Ord a) => [a] -> a

Page 7: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

Pipelines and functions

pipeline architecture widespread in visualization

supports distribution and streaming

However

• Streaming is ad-hoc and coarse grained

• Algorithms depend on mesh type

• Data traversed multiple times

readerozone levels isosurface normals

normalsisosurface

reader

temperature

displaygeo-reference

Note: analogy of pipeline

composition and function

composition: f . g

?

Page 8: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

In the future ... a lazy polytypic grid

Grid enabling: distribution of the run-time system

and on-demand streaming of arbitrary data.

Through fusion laws, multiple traversals on a

single resource are folded into one pass.

2

readerozone levels isosurface normals

normalsisosurface

reader

temperature

geo-reference display

Algorithms: written once, based on generic pattern

of data types, then instantiated for any type.1

3 Specialization: adapt

programs to utilize resources

available – data or

computational.

Page 9: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

9

Marching Cubes

Why do it?

• explore functional visualization

• well known, important algorithm

For each cell

• compare point samples with threshold

• generate case-index

• lookup table to find intersected edges

• interpolate surface-edge intersection

• group intersection points into triangles

Ambiguity problem – various solutions

• “MC33” approach

• tri-linear interpolant

\

Page 10: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

10

Functional arrays

Basic types

type XYZ = (Int,Int,Int)type Num a => Dataset a = Array XYZ atype Cell a = (a,a,a,a,a,a,a,a)

Dataset traversal

isoA :: (Ord a, Integral a) => a -> Dataset a -> [Triangle]isoA th arr = concat $ zipWith1 (mcubeA th lookup) addrs where lookup arr (x,y,z) = (arr!(x,y,z), arr!(x+1,y,z), .., arr!(x+1,y+1,z+1)) addrs = [ (i,j,k) | k <- [1..ksz-1] , j <- [1..jsz-1] , i <- [1..isz-1]] (isz,jsz,ksz) = bounds arr

Cell-surface intersection

mcubeA th lookup xyz = group3 . map (interp th cell xyz) . mctable! . toByte . map8 (>th) $ cell where cell = lookup xyz

not

pseudocode

Page 11: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

11

Can we do better?

entire dataset must be in-core

repeated threshold comparison (once per cell with common vertex)

repeated computation of edge interpolant

• interpolant used by more than one triangle in cell

• surface intersects edge of more than one cell

Page 12: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

12

A window onto samples

Insight – we only need a constant-sized window onto dataset• window size = plane + line + 1 = (jsz+1)*isz + 1

• move from cell-to-cell => advance window by 1

• values read lazily as needed – and gc'd automatically

Haskell representation - a list of values• data Num a => D XYZ [a]

Page 13: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

13

Streams of cells

stream :: XYZ -> [a] -> [Cell a]

stream (isz,jsz,ksz) origin =

zip8 origin (drop 1 origin)

(drop (line+1) origin) (drop line origin)

(drop plane origin) (drop (plane+1) origin)

(drop (planeline+1) origin) (drop planeline origin)

where

line = isz

plane = isz * jsz

planeline = plane + line

8-tu

ple

...

...

...

...

cells

Page 14: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

15

From array to stream

isoA :: (Ord a, Integral a, Fractional b) => a -> Dataset a -> [Triangle b]isoA th sampleArr = concat $ zipWith1 (mcubeA th lookup) addrs where lookup arr (x,y,z) = (arr!(x,y,z), arr!(x+1,y,z), .., arr!(x+1,y+1,z+1)) addrs = [ (i,j,k) | k <- [1..ksz-1] , j <- [1..jsz-1] , i <- [1..isz-1]]mcubeA th lookup xyz = group3 . map (interp th cell xyz) . mctable! . toByte . map8 (>th) $ cell where cell = lookup xyz

Array

isoS th samples = concat $ zipWith2 (mcubeS th) addrs cells where cells = stream size samples addrs = [ (i,j,k) | k <- [1..ksz-1] , j <- [1..jsz-1] , i <- [1..isz-1]]

mcubeS :: (Ord a, Integral a, Fractional b) => a -> XYZ -> Cell a -> [Triangle b]mcubeS th xyz cell = group3 . map (interp th cell xyz) . mctable! . toByte . map8 (>th) $ cell

Stream

Page 15: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

16

Sharing vertex comparison

isoS th samples = concat $ zipWith2 (mcubeS th) addrs cells where cells = stream size samples addrs = [ (i,j,k) | k <- [1..ksz-1] , j <- [1..jsz-1] , i <- [1..isz-1]]

mcubeS :: (Ord a, Integral a, Fractional b) => a -> XYZ -> Cell a -> [Triangle b]mcubeS th xyz cell = group3 . map (interp th cell xyz) . mctable! . toByte . map8 (>th) $ cell

Array

Stream

isoT th samples = concat $ zipWith3 (mcubeT th) addrs cells indices where indices = map toByte . stream . map (>th) cells = ... addrs = ...

mcubeT :: (Ord a, Integral a, Fractional b) => a -> XYZ -> Cell a -> Byte -> [Triangle b]mcubeT th xyz cell index = group3 . map (interp th cell xyz) . mctable! $ index

Indices

Page 16: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

17

Sharing edge interpolants

isoT th samples = concat $ zipWith3 (mcubeT th) addrs cells indices where indices = map toByte . stream . map (>th) cells = ... addrs = ...

mcubeT :: (Num a, Fractional b) -> XYZ -> Cell a -> Byte -> [Triangle b]mcubeT th xyz cell index = group3 . map (interp th cell xyz) . mctable! $ index

Indices

InterpolantsisoI th (D size samples) = concat $ zipWith3 mcubeI addrs indices edges where edges = disContinuities size . mkCellEdges th size indices = ... addrs = ... mcubeI :: (Fractional b) => CellEdge b -> Byte -> XYZ -> [Triangle b]mcubeI xyz index edges = group3 . map (selectEdge edges xyz) . (mctable!) $ index

type CellEdge a = (a, a, a, a, a, a, a, a, a, a, a, a)

mkCellEdges :: (Integral a, Fractional b) => a -> XYZ -> [a] -> [CellEdge b]mkCellEdges thresh (XYZ isz jsz ksz) stream = zipWith12 CellEdge inter_x (drop line inter_x) (drop plane inter_x) (drop (plane+line) inter_x) inter_y (drop 1 inter_y) (drop plane inter_y) (drop (plane+1) inter_y) inter_z (drop 1 inter_z) (drop line inter_z) (drop (line+1) inter_z) where line = isz plane = isz*jsz offset d = zipWith2 interp stream d inter_x = offset (drop 1 stream) inter_y = offset (drop line stream) inter_z = offset (drop plane stream) interpolate v0 v1 = fromIntegral (thresh-v0) / fromIntegral (v1-v0)

Page 17: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

18

Performance - time

Comparison with VTK pipeline

• [raw reader] -> vtkMarchingCubes; outputs retained

• forced evaluation of Haskell output

• comparison ≃ f(surface size)

Dataset Input Window SurfaceTime (seconds)

Array Stream VTK VTK/StreamSilicium 113,288 3,341 103,200 0.626 0.386 0.19 2.03Neghip 262,144 4,161 131,634 1.088 0.852 0.29 2.94Hydrogen 2,097,152 16,513 134,592 8.638 6.694 0.51 13.13Lobster 5,461,344 97,826 1,373,196 25.370 18.420 5.69 3.24Engine 8,388,608 65,793 1,785,720 44.510 28.060 5.29 5.3StatueLeg 10,814,133 116,623 553,554 48.780 78.340 54.2 1.45Aneurism 16,777,216 65,793 1,098,582 72.980 54.440 5.69 9.57Skull 16,777,216 65,793 18,415,053 79.500 57.190 79.03 0.72Stent8 45,613,056 262,657 8,082,312 287.500 154.900 33.17 4.67Vertebra8 134,217,728 262,657 197,497,908 703.000 517.100 755 0.68

Page 18: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

19

Performance - space

Peak live memory usage

• Haskell usage measured by heap profiling

• Stream space use ≃ f(window size)

• Scalabilty without moving to out-of-core methods

Dataset Input Window Surface Array Stream VTK VTK/StreamSilicium 113,288 3,341 103,200 0.12 0.12 1.1 9.17Neghip 262,144 4,161 131,634 0.27 0.14 1.4 9.86Hydrogen 2,097,152 16,513 134,592 2.10 0.55 3 5.45Lobster 5,461,344 97,826 1,373,196 5.45 3.10 19.5 6.29Engine 8,388,608 65,793 1,785,720 8.25 2.10 25.4 12.1StatueLeg 10,814,133 116,623 553,554 11.00 3.72 15.9 4.27Aneurism 16,777,216 65,793 1,098,582 17.00 2.10 28.1 13.38Skull 16,777,216 65,793 18,415,053 17.00 2.13 1855.3 871.03Stent8 45,613,056 262,657 8,082,312 46.00 8.35 119.1 14.26Vertebra8 134,217,728 262,657 197,497,908 137.00 8.35 1300.9 155.8

Page 19: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

20

“Ifs”, “buts”, and “maybe”s

Comparison of apples and oranges?

• only intended as a reality check ...

• vtkMarchingCubes not the fastest VTK surface extraction filter

• VTK pipeline could be fine-tuned, e.g. drop intermediate results

• other implementations

However ...

• our approach can also be tuned further ...

• elegant Haskell not necessarily efficient Haskell

• compiler work, e.g. fusion laws: (map f).(map g) = map (f.g)

Page 20: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

21

Other criteria

Streaming criteria (Law et.al., Proceedings Vis'99)• caching: streamed data access + memoisation• demand-driven:

• natural product of call-by-need (“lazy evaluation”)• data pulled in – and transformed – only to the extent needed

• hardware architecture independence

• polymorphic types supported by type predicates

• Component based:

• library of fine-grained visualization combinators

Clarity• algorithms used in decision making should be evidently correct• strong typing, concise expression, equational reasoning

Page 21: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

22

Outlook

Achievements• novel re-construction of fundamental algorithms

• fine-grained streaming - scalability

• demonstrated that FP can be (surprisingly) efficient

Current work• extending stream approach to other mesh organizations

• exploring polytypism to abstract from organization

• distributing (functional) pipeline over a grid

• exiting distributed FP approaches – GRID-GUM, Eden

• York bytecode compiler (YHC)

Page 22: Fine-grained Visualization Pipelines and Lazy Functional Languages D.J. Duke 1, M. Wallace 2, R. Borgo 1, & C. Runciman 2 1 Visualization and Virtual Reality.

23

Finally

Thanks to:

• EPSRC “Fundamental Computing for e-Science” Programme

• Anonymous reviewers

Further information

• VVR group: www.comp.leeds.ac.uk/vvr/

• Plasma group: www.cs.york.ac.uk/plasma/

• Repository: hackage.haskell.org/trac/PolyFunViz/

• Haskell: www.haskell.org

Questions?