summaryrefslogtreecommitdiff
path: root/docs/ndp/vect.tex
diff options
context:
space:
mode:
Diffstat (limited to 'docs/ndp/vect.tex')
-rw-r--r--docs/ndp/vect.tex363
1 files changed, 0 insertions, 363 deletions
diff --git a/docs/ndp/vect.tex b/docs/ndp/vect.tex
deleted file mode 100644
index bf1e25842b..0000000000
--- a/docs/ndp/vect.tex
+++ /dev/null
@@ -1,363 +0,0 @@
-\documentclass{article}
-\usepackage{haskell}
-
-\hscommand{\vect}[1]{(#1)_v}
-\hscommand{\lift}[2]{(#1)^{\uparrow#2}}
-\hscommand{\liftn}[1]{(#1)^{\uparrow{n}}}
-
-\hscommand{\patype}[1]{\mathsf{patype}\langle#1\rangle}
-\hscommand{\pa}[1]{\mathsf{pa}\langle#1\rangle}
-
-\hscommand{\capp}{\mathbin{{\$}{:}}}
-\hscommand{\cappP}{\mathbin{{\$}{:}^\uparrow}}
-
-\hscommand{\parr}[1]{[{:}{:}#1{:}{:}]}
-\hscommand{\pparr}[1]{[{:}#1{:}]}
-
-\hscommand{\Data}{\hskwd{data}}
-\hscommand{\DataF}{\hskwd{data~family}}
-\hscommand{\DataI}{\hskwd{data~instance}}
-\hscommand{\NewtypeI}{\hskwd{newtype~instance}}
-
-\setlength{\parindent}{0cm}
-
-\begin{document}
-
-\section*{Library}
-
-\subsection*{Parallel arrays}
-
-We distinguish between user-visible, parametric arrays (\<\pparr{\cdot}\>) and
-flattened parallel arrays (\<\parr{\cdot}\>) which are internal to our
-implementation. Operations on the former have purely sequential semantics.
-During vectorisation, they are replaced by parallel arrays and operations.
-
-\begin{haskell}
-\Data \pparr{\alpha} = Array Int \alpha \hscom{or similar} \\
-\DataF \parr{\alpha}
-\end{haskell}
-
-\subsection*{\<PA\> dictionaries}
-
-To avoid problems with using typeclasses in Core, we use explicit records for
-representing dictionaries of type-dependent operations on parallel arrays:
-
-\begin{haskell}
-\Data PA \alpha = & PA \{
- \hsbody{lengthP & :: \parr{\alpha}\to{Int} \\
- replicateP & :: Int\to\alpha\to\parr{\alpha} \\
- \ldots \\ \}}
-\end{haskell}
-
-In vectorised code, polymorphic functions must be supplied with a \<PA\>
-dictionary for each type variable. For instance, \<\Lambda\alpha.e\> turns
-into \<\Lambda\alpha.\lambda{dPA_\alpha}::PA \alpha.e'\>.
-
-For higher-kinded type variables, we expect a function of appropriate type
-which computes the dictionary for a saturated application of the type
-variable from the dictionaries of the arguments. For instance,
-\<\Lambda{m}::{*}\to{*}.e\> turns into
-\<\Lambda{m}::{*}\to{*}.\lambda{dPA_m}::(\forall\alpha::{*}.PA \alpha\to{PA}
-(m a)).e'\>.
-In general, the type of the \<dPA\> argument for a type \<\sigma::\kappa\> is
-given by
-
-\begin{haskell}
-\patype{\sigma:{*}} & = PA \sigma \\
-\patype{\sigma:\kappa_1\to\kappa_2} & =
-\forall\alpha:\kappa_1.\patype{\alpha:\kappa_1}\to\patype{\sigma \alpha:\kappa_2}
-\end{haskell}
-
-For each user-defined or built-in type constructor \<T\> we
-automatically define its dictionary \<dPA_T::\patype{T}\>. Moreover, for every
-in-scope type variable \<\alpha\> we have its dictionary
-\<dPA_\alpha::\patype{\alpha}\>. This allows us to compute the dictionary for
-an arbitrary type as follows:
-
-\begin{haskell}
-\pa{T} & = dPA_T \\
-\pa{\alpha} & = dPA_{\alpha} \\
-\pa{\sigma \phi} & = \pa{\sigma}[\phi] \pa{\phi} \\
-\pa{\forall\alpha::\kappa.\sigma} & =
-\Lambda\alpha::\kappa.\lambda{dPA_{\alpha}}::\patype{\alpha::\kappa}.\pa{\sigma}
-\end{haskell}
-
-\subsection*{Closures}
-
-Closures are represented as follows:
-
-\begin{haskell}
-\Data & Clo \alpha \beta & = \exists\gamma. Clo & (PA \gamma) \gamma
- & (\gamma\to\alpha\to\beta) (\parr{\gamma}\to\parr{\alpha}\to\parr{\beta}) \\
-\DataI & \parr{Clo \alpha \beta} & = \exists\gamma. AClo & (PA \gamma)
- \parr{\gamma}
- & (\gamma\to\alpha\to\beta) (\parr{\gamma}\to\parr{\alpha}\to\parr{\beta})
-\end{haskell}
-
-Closure application is implemented by the following two operators:
-
-\begin{haskell}
-({\capp}) & :: Clo \alpha \beta \to \alpha \to \beta \\
-({\cappP}) & :: \parr{Clo \alpha \beta} \to \parr{\alpha} \to \parr{\beta}
-\end{haskell}
-
-Note that \<({\cappP})\> is effectively the lifted version of \<({\capp})\>.
-
-\subsection*{Flat array representation}
-
-Some important instances of the \<\parr{\cdot}\> family:
-
-\begin{haskell}
-\hskwd{data} & \hskwd{instance} \parr{(\alpha_1,\ldots,\alpha_n)}
- & = ATup_n !Int \parr{\alpha_1} \ldots \parr{\alpha_n} \\
-\hskwd{newtype}~ & \hskwd{instance} \parr{\alpha\to\beta}
- & = AFn (\parr{\alpha}\to\parr{\beta}) \\
-\hskwd{newtype} & \hskwd{instance} \parr{PA \alpha}
- & = APA (PA \alpha)
-\end{haskell}
-
-The last two definitions are discussed later.
-
-\section*{Vectorisation}
-
-\subsection*{Types}
-
-We assume that for each type constructor \<T\>, there exists a vectorised
-version \<T_v\> (which can be the same as \<T\>). In particular, we have
-\begin{haskell}
-({\to}_v) & = Clo \\
-\pparr{\cdot}_v & = \parr{\cdot}
-\end{haskell}
-
-Vectorisation of types is defined as follows:
-
-\begin{haskell}
-\vect{T} & = T_v \\
-\vect{\alpha} & = \alpha \\
-\vect{\sigma \phi} & = \vect{\sigma} \vect{\phi} \\
-\vect{\forall\alpha:\kappa.\sigma} & = \forall\alpha:\kappa.\patype{\alpha:\kappa}\to\vect{\sigma}
-\end{haskell}
-
-\subsection*{Data type declarations}
-
-\begin{haskell}
-\vect{\hskwd{data} T = \overline{C t_1 \ldots t_n}} = \hskwd{data} T_v =
-\overline{C_v \vect{t_1} \ldots \vect{t_n}}
-\end{haskell}
-
-\subsection*{Terms}
-
-We distinguish between local variables (\<x\>) and global variables and
-literals \<c\>. We assume that we have the following typing judgement:
-
-\begin{haskell}
-\Delta,\Gamma\vdash{e}:\sigma
-\end{haskell}
-
-Here, \<\Delta\> assigns types to globals and \<\Gamma\> to locals. Moreover,
-we assume that for each global variable \<c\>, there exists a
-vectorised version \<c_v\>, i.e.,
-
-\begin{haskell}
-c:\sigma\in\Delta \Longrightarrow c_v:\vect{\sigma}\in\Delta
-\end{haskell}
-
-\subsubsection*{Vectorisation}
-
-\begin{haskell}
-\vect{c} & = c_v & c is global \\
-\vect{x} & = x & x is local \\
-\vect{\Lambda\alpha:\kappa.e} & =
-\Lambda\alpha:\kappa.\lambda{dPA_{\alpha}}:\patype{\alpha:\kappa}.\vect{e} \\
-\vect{e[\sigma]} & = \vect{e}[\vect{\sigma}] \pa{\vect{\sigma}} \\
-\vect{e_1 e_2} & = \vect{e_1}\capp\vect{e_2} \\
-\vect{\lambda{x}:\sigma.e} & = Clo \vect{\sigma} \vect{\phi} \tau \pa{\tau}
- (y_1,\dots,y_n) \\
- &
-\quad\quad(\lambda{ys}:\tau.
- \lambda{x}:\vect{\sigma}.
- \hskwd{case} ys \hskwd{of} (y_1,\dots,y_n) \to \vect{e}) \\
- &
-\quad\quad(\lambda{ys}:\parr{\tau}.
- \lambda{x}:\parr{\vect{\sigma}}.
- \hskwd{case} ys \hskwd{of} ATup_n l y_1 \dots y_n \to \lift{e}{l})
-\\
- \hswhere{e has type \phi \\
- \{y_1:\tau_1,\dots,y_n:\tau_n\} & = FVS(e)\setminus{x} \\
- \tau & = (\vect{\tau_1},\dots,\vect{\tau_n})}
-% \\
-% e has type \phi}
-\end{haskell}
-
-Vectorisation maintains the following invariant:
-
-\begin{haskell}
-\Delta,\Gamma\vdash{e}:\sigma \Longrightarrow
- \Delta,\Gamma_v\vdash\vect{e}:\vect{\sigma}
-\end{haskell}
-
-where \<\Gamma_v\> is defined by
-
-\begin{haskell}
-x:\sigma\in\Gamma \Longleftrightarrow x:\vect{\sigma}\in\Gamma_v
-\end{haskell}
-
-\subsubsection*{Lifting}
-\begin{haskell}
-\liftn{c:\sigma} & = replicateP \pa{\vect{\sigma}} n c_v \\
-\liftn{x} & = x \\
-\liftn{\Lambda\alpha:\kappa.e} & =
-\Lambda\alpha:\kappa.\lambda{dPA_{\alpha}}:\patype{\alpha:\kappa}.\liftn{e} \\
-\liftn{e[\sigma]} & = \liftn{e}[\vect{\sigma}] \pa{\vect{\sigma}} \\
-\liftn{e_1 e_2} & = \liftn{e_1} \cappP \liftn{e_2} \\
-\liftn{\lambda{x}:\sigma.e} & = AClo \vect{\sigma} \vect{\phi} \vect{\tau}
- \pa{\vect{\tau}}
- (ATup_n y_1 \dots y_n) \\
- &
-\quad\quad(\lambda{ys}:\vect{\tau}.
- \lambda{x}:\vect{\sigma}.
- \hskwd{case} ys \hskwd{of} (y_1,\dots,y_n) \to \vect{e}) \\
- &
-\quad\quad(\lambda{ys}:\parr{\vect{\tau}}.
- \lambda{x}:\parr{\vect{\sigma}}.
- \hskwd{case} ys \hskwd{of} ATup_n l y_1 \dots y_n \to \lift{e}{l})
- \hswhere{e has type \phi \\
- \{y_1:\tau_1,\dots,y_n:\tau_n\} & = FVS(e)\setminus{x} \\
- \tau & = (\tau_1,\dots,\tau_n)}
-\end{haskell}
-
-Lifting maintains the following invariant:
-
-\begin{haskell}
-\Delta,\Gamma\vdash{e}:\sigma \Longrightarrow
- \Delta,\Gamma^\uparrow\vdash\liftn{e} : \parr{\sigma_v}
-\end{haskell}
-
-where
-
-\begin{haskell}
-x:\sigma\in\Gamma \Longleftrightarrow x:\parr{\vect{\sigma}}\in\Gamma^\uparrow
-\end{haskell}
-
-Note that this is precisely the reason for the \<\parr{\cdot}\> instances for
-\<\alpha\to\beta\> and \<PA \alpha\>. A term of type \<\forall\alpha.\sigma\>
-will be lifted to a term of type
-\<\parr{\forall\alpha.PA \alpha\to\vect{\sigma}}\> which requires the
-instances. Apart from closures, these are the only occurrences of \<({\to})\> in
-the transformed program, however.
-
-
-\section*{What to vectorise?}
-
-An expression is vectorisable if it only mentions globals and type constructors
-which have a vectorised form. When vectorising, we look for maximal
-vectorisable subexpressions and transform those. For instance, assuming that
-\<print\> hasn't been vectorised, in
-
-\begin{haskell}
-main = \hsdo{
- print (sumP \pparr{\ldots}) \\
- print (mapP \ldots \pparr{\ldots})}
-\end{haskell}
-
-we would vectorise the arguments to \<print\>. Note that this implies that we
-never call non-vectorised code from vectorised code (is that a problem?).
-
-Whenever we come out of a vectorised ``bubble'', we have to convert between
-vectorised and unvectorised data types. The examples above would roughly
-translate to
-
-\begin{haskell}
-main = \hsdo{
- print (unvect (sumP_v \parr{\ldots})) \\
- print (unvect (mapP_v \ldots \parr{\ldots}))}
-\end{haskell}
-
-For this, we have to have the following functions:
-
-\begin{haskell}
-vect_\sigma & :: \sigma\to\vect{\sigma} \\
-unvect_\sigma & :: \vect{\sigma}\to\sigma
-\end{haskell}
-
-It is sufficient to have these functions only for a restricted set of types as
-we can always vectorise less if the conversions becomes too complex.
-
-Sometimes, it doesn't make sense to vectorise things. For instance, in
-
-\begin{haskell}
-foo f xs = print (f xs)
-\end{haskell}
-
-we wouldn't vectorise \<f xs\>. Unfortunately, this means that
-\<foo (mapP f) xs\> will be purely sequential.
-
-For each expression, the vectoriser gives one of the following answers.
-
-\begin{tabular}{lp{10cm}}
-\textbf{Yes} &
-the expression can be (and has been) vectorised \\
-\textbf{Maybe} &
-the expression can be vectorised but it doesn't make sense to do so
-unless it is used in a vectrorisable context (e.g., for \<f xs\> in \<foo\>)
-\\
-\textbf{No} &
-the expression can't be vectorised (although parts of it can, so we
-still get back a transformed expression)
-\end{tabular}
-
-\subsection*{Top-level definitions}
-
-For a top-level definition of the form
-
-\begin{haskell}
-f :: \sigma = e
-\end{haskell}
-
-vectorisation proceeds as follows.
-
-\begin{itemize}
-\item If \<e\> can be fully vectorised, we generate
-\begin{haskell}
-f_v :: \vect{\sigma} = \vect{e}
-\end{haskell}
-
-\item If it doesn't always make sense to vectorise \<e\>, i.e., the vectoriser
-returned \textbf{Maybe}, we leave the definition of \<f\> unchanged. Thus, we
-would not change
-\begin{haskell}
-({\$}) = \lambda{f}.\lambda{x}.f x
-\end{haskell}
-but would additionally generate
-\begin{haskell}
-({\$}_v) = Clo \ldots
-\end{haskell}
-
-\item Otherwise (if the vectoriser said \textbf{Yes}) and we have
-\<unconv_\sigma\>, we change the definition of \<f\> to
-\begin{haskell}
-f :: \sigma = unconv_\sigma f_v
-\end{haskell}
-
-\item Otherwise (the vectoriser said \textbf{Yes} but we do not have
-\<unconv_\sigma\> or if \<e\> couldn't be fully vectorised), we change the
-definition of \<f\> to
-\begin{haskell}
-f :: \sigma = e'
-\end{haskell}
-where \<e'\> is obtaining by vectorising \<e\> as much as possible without
-changing its type. For instance, for
-\begin{haskell}
-f = \lambda{g}.\lambda{x}.mapP (\ldots) (g x)
-\end{haskell}
-we would generate
-\begin{haskell}
-f & = \lambda{g}.\lambda{x}.unvect (mapP_v (\ldots) (vect (g x))) \\
-f_v & = Clo \ldots
-\end{haskell}
-assuming we have the necessary conversions but cannot convert functions (i.e.,
-\<g\>).
-\end{itemize}
-
-\end{document}
-