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
22
Embed
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.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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
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
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
4
What is (pure) functional programming?
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”
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
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
?
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.
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
\
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
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
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)