\section{Extensions}
\label{sec-extensions}

\CYS supports some extensions in Curry programs that are not (yet)
part of the definition of Curry. These extensions are described below.

\subsection{Recursive Variable Bindings}

Local variable declarations (introduced by \code{let}\pindex{let}
or \code{where}\pindex{where}) can be (mutually) recursive in \CYS.
For instance, the declaration
\begin{curry}
ones5 = let ones = 1 : ones
         in take 5 ones
\end{curry}
introduces the local variable \code{ones} which is bound
to a \emph{cyclic structure}\index{cyclic structure}
representing an infinite list of \code{1}'s.
Similarly, the definition
\begin{curry}
onetwo n = take n one2
 where
   one2 = 1 : two1
   two1 = 2 : one2
\end{curry}
introduces a local variables \code{one2} that represents
an infinite list of alternating \code{1}'s and \code{2}'s
so that the expression \code{(onetwo 6)} evaluates to \code{[1,2,1,2,1,2]}.

\subsection{Functional Patterns}

Functional patterns \cite{AntoyHanus05LOPSTR} are a useful extension
to implement operations in a more readable way. Furthermore,
defining operations with functional patterns avoids problems
caused by strict equality (\ccode{=:=}) and leads to programs
that are potentially more efficient.

Consider the definition of an operation to compute the last element
of a list \code{xs} based on the prelude operation \ccode{++}
for list concatenation:
\begin{curry}
last xs | _++[y] =:= xs  = y   where y free
\end{curry}
Since the equality constraint \ccode{=:=} evaluates both sides
to a constructor term, all elements of the list \code{xs} are
fully evaluated in order to satisfy the constraint.

Functional patterns can help to improve this computational behavior.
A \emph{functional pattern}\index{functional pattern}\index{pattern!functional}
is a function call at a pattern position. With functional patterns,
we can define the operation \code{last} as follows:
\begin{curry}
last (_++[y]) = y
\end{curry}
This definition is not only more compact but also avoids the complete
evaluation of the list elements: since a functional pattern is considered
as an abbreviation for the set of constructor terms obtained by all
evaluations of the functional pattern to normal form (see
\cite{AntoyHanus05LOPSTR} for an exact definition), the previous
definition is conceptually equivalent to the set of rules
\begin{curry}
last [y] = y
last [_,y] = y
last [_,_,y] = y
$\ldots$
\end{curry}
which shows that the evaluation of the list elements is not demanded
by the functional pattern.

In general, a pattern of the form \code{($f$ $t_1$\ldots$t_n$)} for $n>0$
(or of the qualified form \code{($M.f$ $t_1$\ldots$t_n$)} for $n \geq 0$)
is interpreted as a functional pattern if $f$ is not a visible constructor
but a defined function that is visible in the scope of the pattern.
Furthermore, for a functional pattern to be well defined,
there are two additional requirements to be satisfied:

\begin{enumerate}

\item
If a function $f$ is defined by means of a functional pattern $fp$,
then the evaluation of $fp$ must not depend on $f$, i.e.,
the semantics of a function defined using functional patterns
must not (transitively) depend on its own definition.
This excludes definitions such as
\begin{curry}
(xs ++ ys) ++ zs = xs ++ (ys ++ zs)
\end{curry}
and is necessary to assign a semantics to funtions employing functional patterns
(see \cite{AntoyHanus05LOPSTR} for more details).

\item
Only functions that are globally defined may occur inside a functional pattern.
This restriction ensures that no local variable
might occur in the value of a functional pattern,
which might lead to an non-intuitive semantics.
Consider, for instance, the following (complicated) equality operation
\begin{curry}
eq :: a -> a -> Bool
eq x y = h y
 where
  g True  = x
  h (g a) = a
\end{curry}
where the locally defined function \code{g} occurs in the functional
pattern \code{(g a)} of \code{h}.
Since \code{(g a)} evaluates to the value of \code{x} whereas \code{a}
is instantiated to \code{True}, the call \code{h y} now evaluates to \code{True}
if the value of \code{y} equals the value of \code{x}.
In order to check this equality condition,
a strict unification between \code{x} and \code{y} is required
so that an equivalent definition without functional patterns would be:
\begin{curry}
eq :: a -> a -> Bool
eq x y = h y
 where
  h x1 | x =:= x1 = True
\end{curry}
However, this implies that variables occuring in the value
of a functional pattern imply a strict unification
if they are defined in an outer scope,
whereas variables defined \emph{inside} a functional pattern
behave like pattern variables.
In consequence, the occurrence of variables from an outer scope
inside a functional pattern might lead to an non-intuitive behavior.
To avoid such problems, locally defined functions are excluded
as functional patterns.
Note that this does not exclude a functional pattern inside a local function,
which is still perfectly reasonable.
\end{enumerate}
%
It is also possible to combine functional patterns with
as-patterns.\index{as-pattern}\pindex{"@}
Similarly to the meaning of as-patterns
in standard constructor patterns,
as-patterns in functional patterns are interpreted
as a sequence of pattern matching where the variable of the as-pattern
is matched before the given pattern is matched.
This process can be described by introducing an auxiliary operation
for this two-level pattern matching process.
For instance, the definition
\begin{curry}
f (_ ++ x@[(42,_)] ++ _) = x
\end{curry}
is considered as syntactic sugar for the expanded definition
\begin{curry}
f (_ ++ x ++ _) = f' x
 where
  f' [(42,_)] = x
\end{curry}
However, as-patterns are usually implemented
in a more efficient way without introducing auxiliary operations.

\paragraph{Optimization of programs containing functional patterns.}
Since functions patterns can evaluate to non-linear constructor terms,
they are dynamically checked for multiple occurrences of
variables which are, if present, replaced by equality constraints
so that the constructor term is always linear
(see \cite{AntoyHanus05LOPSTR} for details).
Since these dynamic checks are costly and not necessary for
functional patterns that are guaranteed to evaluate to linear terms,
there is an optimizer for functional patterns that checks
for occurrences of functional patterns that evaluate always to
linear constructor terms and replace such occurrences
with a more efficient implementation.
This optimizer can be enabled by the following possibilities:
\begin{itemize}
\item
Set the environment variable \code{FCYPP} to \ccode{--fpopt}
before starting \CYS, e.g., by the shell command
\begin{curry}
export FCYPP="--fpopt"
\end{curry}
Then the functional pattern optimization is applied if programs are compiled
and loaded in \CYS.
\item
Put an option into the source code:
If the source code of a program
contains a line with a comment of the form (the comment
must start at the beginning of the line)
\begin{curry}
{-# PAKCS_OPTION_FCYPP --fpopt #-}
\end{curry}
then the functional pattern optimization is applied
if this program is compiled and loaded in \CYS.
\end{itemize}
The optimizer also report errors in case of wrong uses of functional patterns
(i.e., in case of a function $f$ defined with functional patterns that
recursively depend on $f$).

\subsection{Order of Pattern Matching}

Curry allows multiple occurrences of pattern variables
in standard patterns. These are an abbreviation of equational constraints
between pattern variables.
Functional patterns might also contain multiple occurrences of
pattern variables.
For instance, the operation
\begin{curry}
f (_++[x]++_++[x]++_) = x
\end{curry}
returns all elements with at least two occurrences in a list.

If functional patterns as well as multiple occurrences of
pattern variables occur in a pattern defining an operation,
there are various orders to match an expression against such
an operation. In the current implementation, the order
is as follows:
\begin{enumerate}
\item Standard pattern matching: First, it is checked whether
the constructor patterns match. Thus, functional patterns
and multiple occurrences of pattern variables are ignored.
\item Functional pattern matching: In the next phase,
functional patterns are matched but occurrences of standard
pattern variables in the functional patterns are ignored.
\item Non-linear patterns: If standard and functional pattern matching
is successful, the equational constraints which correspond
to multiple occurrences pattern variables are solved.
\item Guards: Finally, the guards supplied by the programmer
are checked.
\end{enumerate}
The order of pattern matching should not influence the computed
result. However, it might have some influence on the termination
behavior of programs, i.e., a program might not terminate
instead of finitely failing.
In such cases, it could be necessary to consider the influence
of the order of pattern matching. Note that other orders of pattern matching
can be obtained using auxiliary operations.

\subsection{Type Classes}

The concept of type classes is not yet part of the Curry language report.
The recognized syntax of type classes is specified in
Section~\ref{sec:syntax}.
Although the implemented concept of type classes
is not fully described in this manual,
it is quite similar to Haskell 98 \cite{PeytonJones03Haskell}
so that one can look there to find a detailed description.

%%% Local Variables:
%%% mode: latex
%%% TeX-master: "manual"
%%% End:


\documentclass{vldb}
\usepackage{balance}  % for  \balance command ON LAST PAGE  (only there!)
\usepackage{enumitem}
%\usepackage{natbib}
\usepackage{setspace}
\usepackage{geometry}                % See geometry.pdf to learn the layout options. There are lots.
%\geometry{letterpaper}                   % ... or a4paper or a5paper or ...
%\geometry{landscape}                % Activate for for rotated page geometry
%\usepackage[parfill]{parskip}    % Activate to begin paragraphs with an empty line rather than an indent
\usepackage{graphicx}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{epstopdf}
\usepackage{url}
\usepackage{mathtools}
\DeclarePairedDelimiter{\ceil}{\lceil}{\rceil}
\DeclarePairedDelimiter{\floor}{\lfloor}{\rfloor}
\DeclareMathOperator*{\argmax}{arg\,max}
\DeclareMathOperator{\argmin}{arg\,min}

\vldbTitle{ Extremely Accurate Quantiles Using t-Digests}
\vldbAuthors{Ted Dunning, Otmar Ertl}
\vldbDOI{https://doi.org/10.14778/xxxxxxx.xxxxxxx}
\vldbVolume{xx}
\vldbNumber{xxx}
\vldbYear{2019}

\begin{document}
\title{ Extremely Accurate Quantiles Using t-Digests}

\numberofauthors{2}
\author{
% You can go ahead and credit any number of authors here,
% e.g. one 'row of three' or two rows (consisting of one row of three
% and a second row of one, two or three).
%
% The command \alignauthor (no curly braces needed) should
% precede each author name, affiliation/snail-mail address and
% e-mail address. Additionally, tag each line of
% affiliation/address with \affaddr, and tag the
% e-mail address with \email.
%
% 1st. author
\alignauthor
Ted Dunning\titlenote{Corresponding author}\\
       \affaddr{MapR Technologies}\\
       \affaddr{Santa Clara, CA}\\
       \email{ted.dunning@gmail.com}
% 2nd. author
\alignauthor
Otmar Ertl\\
       \affaddr{Dynatrace}\\
       \affaddr{Linz, Austria}
       \email{otmar.ertl@gmail.com}
}
\date{17 March 2019}

\maketitle

\begin{abstract}
We introduce a new class of quantile-estimation algorithms based on a novel data structure we have developed, the $t$-digest. The $t$-digest  provides a way to compute a compact sketch of the empirical distribution of real-valued samples. These sketches allow approximate quantiles of the samples to be computed. These estimates are fast, accurate and support a number of use cases where approximate quantiles of a large amount of data are needed. One particularly novel property of the $t$-digest is a focus on  accuracy of quantiles  relative to $\max(q, 1-q)$ rather than absolute accuracy as with most other methods for distribution estimation.  The $t$-digest is robust with respect to skewed distributions or ordered datasets and allows separately computed summaries to be combined with no loss in accuracy. Though previously unpublished, the $t$-digest and associated algorithms are already in wide use.

An open-source reference implementation is available in Java from the author. Independent implementations in C++, Go and Python are also available.

% Please include a maximum of seven keywords
%\keywords{quantiles, median, rank statistics, t-digest}
\end{abstract}
\maketitle
\section{Introduction}
Given a set of real-valued samples $x_1 \ldots x_n$, it is often important to be able to estimate the quantile $q$ of a particular value $x$ with respect to the empirical distribution of the samples. This is trivial to compute if all of the samples can be retained but can only be approximated if they cannot \cite{munro1980}. The inverse problem of computing $x$ given $q$ is also important and  can similarly only be approximated unless all of the original data is retained.

The algorithm described here, the $t$-digest, allows accurate approximations of $q$ given $x$ or $x$ given $q$, but it is unusual in that it minimizes errors relative to $\max(q, 1-q)$ as opposed to  absolute error independent of $q$. Relative error is much more useful than absolute error because it makes little practical sense to estimate the median with the same precision as, say, the 99.999-th percentile.

This estimation with small relative error is done while maintaining a very small sketch of the data that is strictly bounded in terms of size. This  sketch is constructed by clustering the original data and retaining only the average value and number of samples for each cluster. The clusters near $q=0$ or $q=1$ can be kept much smaller than for interior values of $q$. This limit on size keeps errors  smaller near those boundaries. The clustering is done in a novel way that preserves the invariants on size and number of clusters even for adversarially chosen samples. Traditionally, quantile estimation algorithms have binned data based on boundaries chosen such that each bin is roughly equal in size.
Keeping the centroid of each cluster as in a $t$-digest rather than maintaining bin boundaries is what makes it possible to enforce the invariants and thus control cluster sizes and relative error. This approach also
 makes it feasible to merge digests that are constructed independently, allowing $t$-digests to be computed in parallel or pre-aggregated for fast OLAP-like queries. An open source reference implementation is available \cite{t-digest-project}.

The $t$-digest is particularly useful in monitoring applications where it is important to be able to determine whether a particular value is unusual or to detect changes in the distribution of values. It can also be used in databases for estimating data distribution or in decision trees to choose decision-points accurately.

\subsection{Previous work}

One early algorithm for computing on-line quantiles is described by Chen et al\cite{Chen2000}.  In that work specific quantiles were computed by incrementing or decrementing an estimate by a value proportional to the simultaneously estimated probability density at the desired quantile.  This method is plagued by a circularity in that estimating density is only possible by estimating yet more quantiles.  Moreover, this work did not produce a sketch that would allow approximating any quantile, nor was it feasable to use for computing hybrid quantities such as trimmed means.

Munro and Paterson \cite{munro1980} provided an alternative algorithm to get a precise estimate of the median.  This worked by keeping $s$ samples from the $N$ samples seen so far where $s << N$ by the time the entire data set has been seen.  If the data are presented in random order and if $s = \theta(N^{1/2} \log N)$, then Munro and Paterson's algorithm has a high probability of being able to retain a set of samples that contains the median.  This algorithm can be adapted to find a number of pre-specified quantiles at the same time at proportional cost in memory.  The memory consumption of Munro-Paterson algorithm is, however, excessive if precise results are desired.  Approximate results can be had with less memory, however.

A more subtle problem is that the Sawzall implementation of Munro and Paterson's algorithm\cite{sawzall} and the Datafu library\cite{datafu} uses a number of buckets computed from the least common multiple of the desired quantiles.  This means that if you want to compute the $99$-th, $99.9$-th and $99.99$-th percentiles using Munro and Paterson's algorithm, ten thousand buckets are required, each of which requires the retention of many samples. This makes Munro and Paterson's algorithm infeasible for general quantile approximation.

One of the most important results of the work by Munro and Paterson was a proof that computing any particular quantile in $p$ passes through the data requires $\Omega(N^{1/p})$ memory. For the on-line case, $p=1$, this implies that on-line algorithms cannot guarantee a precise value of any particular quantile. This result together with the importance of the on-line case drove subsequent work to focus on algorithms to produce approximate values of quantiles.

Greenwald and Khanna\cite{Greenwald-space-efficient-online-quantiles} provided just such an approximation algorithm that is able to provide estimates of quantiles with controllable accuracy. This algorithm requires less memory than Munro and Paterson's algorithm and provides approximate values for pre-specified quantiles. However, the need to pre-specify the desired quantiles makes Greenwald and Khanna's algorithm unsuitable as a general-purpose sketching algorithm.

An alternative approach is described by Shrivastava et al \cite{qdigest}.  In this work, incoming values are assumed to be integers of fixed size. Such integers can trivially be arranged in a perfectly balanced binary tree where the leaves correspond to the integers and the interior nodes correspond to bit-wise prefixes. This tree forms the basis of the data structure known as a Q-digest.  The idea behind a Q-digest is that, in the uncompressed case, counts for various values are assigned to leaves of the tree.  To compress this tree, sub-trees are collapsed and counts from the leaves are aggregated into a single node representing the sub-tree such that the maximum count for any collapsed sub-tree is less than a threshold that is a small fraction of the total number of integers seen so far.  Any quantile can be computed by traversing the tree in left prefix order, adding up counts until the desired fraction of the total is reached.  At that point, the count for the last sub-tree traversed can be used to interpolate to the desired quantile within a small and controllable error.  The error is bounded because the count for each collapsed sub-tree is bounded.

The salient virtues of the Q-digest are
\begin{itemize}[nosep, topsep=-10pt]
\item the space required is bounded proportional to a compression factor $k$
\item the maximum error of any quantile estimate is proportional to $1/k$ and
\item the desired quantiles do not have to be specified in advance.
\vspace{10pt}
\end{itemize}

On the other hand, there are problems with the Q-digest that  limit its applicability. These include:
\begin{itemize}[nosep, topsep=-10pt]
\item  the set of possible values must be known in advance to be integers from a strictly limited range
\item  the Q-digest produces quantile estimates have constant absolute error with respect to $q$
\vspace{10pt}
\end{itemize}

Adapting the Q-digest to use a balanced tree over arbitrary elements of an ordered set is difficult.  This difficulty arises because rebalancing the tree involves sub-tree rotations and these rotations may require reapportionment of previously collapsed counts in complex ways.  This reapportionment could have substantial effects on the accuracy of the algorithm and in any case make the implementation much more complex because the concerns of counting cannot be separated from the concerns of maintaining a balanced tree.

In recent work, Gan et al \cite{Gan:2018:MQS:3236187.3269475} have developed a sketching algorithm that retains moments of the data seen so far. Quantiles can be reconstructed using these moments with roughly constant absolute error. Because the moments are ultimately based on sums, these sketches support very fast merging of a large number of sketches. The motivation for fast merging stems from system monitoring applications where it is useful to support large queries of historical databases. Unfortunately, the algorithm exhibits very poor numerical stability when applied to data that is not centered near $0$ due to the use of higher order moments. As a result, the currently available version of moment sketches can only achieve 1\% average error for distributions with offsets less than the range of the distribution. Examples of problematic distributions include human body temperatures, altitudes above sea level in a city like Denver or amount of disk space in use on a computer over a period of weeks. When presented with data with an offset distribution, the currently available moment sketch implementation simply fails to converge when the default configuration is used to compute quantiles of offset distributions or fails to give accurate results if the number of moments is limited.

In summary, previous work described in this section leaves several important requirements for practical application unmet. Only the Q-digest and Gan et al's moment sketches produce general purpose sketches, but neither of these methods can produce a sketch from arbitrary real-valued data and neither estimates quantiles with controlled relative error. In the next section, we describe the $t$-digest, which rectifies both of these limitations.

\section{ $T$-digest algorithms}
A $t$-digest is a partition of the samples $x_1 \ldots x_n$ into clusters where the size of each cluster is limited to minimize errors and where the points in each cluster are (almost) ordered with respect to points in other clusters.

By convention, we order the clusters according to their means, breaking ties arbitrarily. That is
\begin{equation*}
i > j \implies \mu(\mathcal C_i) \ge \mu(\mathcal C_j)
\end{equation*}
where $\mu(\mathcal C)$ indicates the mean of the points in cluster $\mathcal C$.

In a $t$-digest, the limit on the size of clusters is imposed using a so-called scale function $k(q)$ that maps quantile $q$ into a real-valued index $k$. Each cluster is limited in size by requiring that the difference in value of $k(q)$ on each side of a particular cluster be less than $1$. More precisely, for a particular cluster $\mathcal C_i$, define $\mathcal W_{\mathrm {left}}(\mathcal C_i) = \sum_{j<i} |\mathcal C_j|$ as the sum of the sizes of all clusters with means less than the mean of $\mathcal C_i$. The $k$-size of cluster $\mathcal C_i$ is defined as
\begin{equation}
{|\mathcal C_i |}_k = k\left(\mathcal W_{\mathrm{left}} (\mathcal C_{i+1}) \right) - k\left(\mathcal W_{\mathrm{left}} (\mathcal C_{i}) \right)
\end{equation}
A $t$-digest is defined so that the $k$ size of all clusters with more than one member is less than $1$. \begin{equation}\label{eq:size-limit}
{|\mathcal C_i |}_k \le 1
\end{equation}
Such a digest is referred to as fully merged if
\begin{equation}
{|\mathcal C_i |}_k+{|\mathcal C_{i+1} |}_k > 1
\end{equation}
Such a $t$-digest can be constructed by sorting  the samples $x_1 \ldots x_n$ and then accumulating them into clusters subject to the size constraints. This clustering is not unique and depends on the order that  points are accumulated. The clusters in a digest constructed this way are said to be strictly ordered if the ordering of the means of two clusters defines the ordering of any pair of samples from the two clusters:
\begin{equation}\label{eq:weak-ordering}
 i > j \implies x \ge y \mathrm{\,for\,} x \in \pi_i \mathrm{\,and\,} y \in \pi_j
 \end{equation}
We refer to a digest as weakly ordered if
\begin{equation}\label{eq:strong-ordering}
 i > j+\Delta \implies x \ge y \mathrm{\,for\,} x \in \pi_i \mathrm{\,and\,} y \in \pi_j
 \end{equation}
for some positive offset $\Delta\ge 1$.

Constructing a $t$-digest by sorting all of the samples is of little practical interest since having all of the samples would mean that there is little need for the $t$-digest in the first place. We can do nearly as well, however, if we construct digests by adding batches of samples and then merging clusters and points as much as possible after each batch is added. The result of this merging will be a weakly ordered digest, but the ordering of the resulting digest is good enough (i.e. $\Delta$ is small enough) to allow very accurate quantile estimates. Moreover, random ordering of data is the worst case for accuracy; if the samples are ordered or nearly ordered, the resulting digest will be more strongly ordered and give more accurate estimates.
\subsection{Scale Functions}
The scale function can be chosen and parameterized to control the trade off between accuracy and size of a digest and to adjust the emphasis on accuracy for extreme quantiles. There are four scale functions that have been characterized to date,
\begin{align}
k_0(q) &= \frac \delta 2 q \\
k_1(q) &= \frac \delta {2\pi}  \sin^{-1}(2q-1)   \\
k_2(q) &= \frac \delta {4 \log n/\delta + 24} \log {\frac q {1-q}} \\
k_3(q) &= \frac \delta {4\log n/\delta + 21}\begin{cases}
\quad \log 2q & \text{if  } q \le 1/2 \\
- \log 2(1-q) & \text{if  } q > 1/2
\end{cases}
\end{align}
Of these, $k_0$ provides equal emphasis on absolute error for all values of $q$ and thus results in roughly equal-sized clusters. In contrast, $k_2$ and $k_3$ force the first and last few clusters to be much smaller and thus control relative error best of these four. Function $k_1$ was the first scale function developed, but is currently provided primarily for backward compatibility since it generally does not control relative accuracy as well as $k_2$ or $k_3$. In all of these scale functions, the factor, $\delta$, is known as the compression factor and serves the common purpose of controlling how many clusters a $t$-digest will contain; once the number of samples added to the digest is large enough, the number of clusters is constrained to  between $\delta/2$ and $\delta$.

In addition to bounding the size of $\delta$ all of these scale functions are guaranteed to preserve the invariance of the fundamental size limit of a $t$-digest in Equation \ref{eq:size-limit}. This invariance holds no matter how the data is ordered and regardless of the order that digests are merged.

Figure \ref{fig:k-q-plot} shows scale function $k_1$ with $\delta=10$.
\begin{figure}[htbp] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=2.5in]{figures/k-q-plot.pdf}
   \caption{The scale function translates the quantile $q$ to the scale factor $k$ in order to give variable size steps in $q$. Limiting cluster sizes allows better accuracy near $q=0$ or $q=1$. }
   \label{fig:k-q-plot}
\end{figure}
In this figure, the horizontal lines are spaced uniformly at integer values of $k$. Vertical lines are drawn from the intersection of the scale function with these evenly spaced horizontals. The  vertical lines near $q=0$ and $q=1$ are spaced more closely,  illustrating how clusters there will be kept smaller than near the median. Proceeding from $k_0$ to $k_3$, each scale function is progressively steeper near $q=0$ and $q=1$ forcing the first and last few clusters to be progressively smaller. Scale functions $k_1$ and $k_2$ are similar, except that the value of $k$ at $q=0$ and $q=1$ is infinite. The practical impact of these infinite tails is to force the first and last cluster to have only a single sample.
Scale function $k_0$, in contrast, is linear which results in roughly equal sized clusters.

Smaller clusters give smaller errors in estimating quantiles because the interpolated empirical cumulative distribution function tracks the actual empirical distribution more closely. This difference is illustrated in Figure \ref{fig:linear-interpolation}.
\begin{figure*}[htb] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[height=2.in, clip]{figures/linear-interpolation.pdf}
   \caption{The left panel shows linear interpolation of the cumulative distribution function near $q=0$ with $100$ equal sized clusters applied to $10,000$ data points sampled from an exponential distribution. The right panel shows the same interpolation with variable size clusters as given by a strongly ordered $t$-digest with $\delta=100$. The numbers above the data points represent the number of points in each cluster. Smaller clusters make interpolation more accurate.}
   \label{fig:linear-interpolation}
\end{figure*}
This figure shows roughly the first percentile of 10,000 data points sampled using $x \sim \log  \mathrm{Uniform}(0,1)$. In the left panel, the data points have been divided into 100 clusters, each with 100 data points, of which only the first bin is visible. The use of equal sized bins means that the linearly interpolated value of $q$ in the left panel of the figure has a substantial and unavoidable error. The right panel, on the other hand, shows a $t$-digest with roughly the same number of bins ($102$ instead of $100$), but with many fewer points in bins near  $q=0$. Obviously, the relationship between $x$ and $q$ can be estimated more precisely with these smaller clusters.

Of course, since every sample must be in some cluster, filling some clusters with fewer than $100$ samples requires that some other cluster or clusters must have more than $100$ samples, or we have to have more clusters.

In the particular example shown in Figure \ref{fig:linear-interpolation}, the first bin has only 2 samples and thus zero error and the second bin has only 10 samples giving much smaller error than a cluster of $100$ samples would give. The clusters near $q=1/2$, on the other hand, have about $1.6$ times more samples than the uniform case, increasing errors by only a modest factor relative to equal sized bins. The overall effect is that quantile estimation accuracy is dramatically improved at the extremes but only modestly impaired near the median. Exactly how much accuracy at the tails is improved depends on the choice of scale function and, crucially, on how close the $t$-digest is to being strictly ordered.

\subsection{Stratified Merging}
If the clusters in a $t$-digest overlap substantially, the accuracy of the interpolated quantile estimates will be  impaired. In order to decrease that overlap, the $t$-digest library by default uses a higher value of $\delta$ while data is being added to a digest and then decreases $\delta$ when the digest is persisted. This can be done without increasing the memory requirements of the digest, but there is a cost in terms of speed since more of the memory used in the digest is devoted to clusters and less memory is used for incoming samples. That means that new data has to be merged a bit more often, and each merge takes a bit more time. In practice, the improvement in accuracy is dramatic while the cost in speed is modest, making this a good tradeoff.

The tradeoff represented in stratified merging ranges from one extreme of no stratification at all to the case where the intermediate value of $\delta$ is so large that nearly all memory is consumed by clusters and there is no room for buffered samples resulting in very large slowdown. In current implementations, a heuristic is used in which the intermediate value of $\delta$ is the geometric mean of the buffer size and the final value of $\delta$. This strategy has not been subjected to deep analysis, but  in practice it seems to be a reasonable middle ground between better accuracy and higher overhead.
\subsection{Degree of overlap of t-digest clusters}
Figure \ref{fig:cluster-spread} shows how effective the stratified merging strategy  is at producing high quality clusters. This requires about 20\% more merge operations and  each merge operation is typically less than twice as expensive. The resulting clusters are not quite strictly ordered, but overlap between clusters is limited to adjacent clusters.
\begin{figure}[htb] %  figure placement: here, top, bottom, or page
\center
   \includegraphics[width=3in]{figures/cluster-spread.pdf}
   \caption{This typical $t$-digest is not strictly ordered, but only adjacent clusters overlap. In these first 16 clusters odd clusters overlap with adjacent even clusters, but never with adjacent odd clusters. Similarly, even clusters do not overlap with even ones.
This corresponds to weak ordering with $\Delta=1$. Note also that the first three clusters are all singletons which drives estimation errors to zero roughly where $q < 5 \times 10^{-5}$.  }
   \label{fig:cluster-spread}
\end{figure}
The digest shown in Figure \ref{fig:cluster-spread} was produced by inserting $10^6$ samples using a working compression of $\delta = 316$ and alternating the direction of merges. The final digest was produced by doing a final merge step with $\delta = 100$, resulting in a roughly $3:1$ merge of the working clusters. With unidirectional merge steps and keeping $\delta=100$ during construction, the overlap between clusters commonly extends to the adjacent 3-4 clusters, thus degrading accuracy.
\begin{figure*}[htb] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=5in]{figures/merge.pdf}
   \caption{Accuracy of a $t$-digest formed by merging sub-digests from equal-sized partitions is as good or better than a digest accumulated on all of the data at once if the sub-digests have a larger value of $\delta$ than the final desired value. All panels were computed by 20 repetitions of aggregating 1,000,000 values.}
   \label{fig:merge}
\end{figure*}

\subsection{The clustering variant}
If we allow the buffer in the merging variant of the $t$-digest algorithm to contain just a single element so that merges can take place every time a new point is added, the algorithm takes on a new character and becomes much more like traditional $k$-means clustering than like a buffer and merge algorithm.

The basic outline of the clustering algorithm for constructing a $t$-digest is quite simple.  An initially empty ordered list of clusters $C = [ \mathcal C_1 \ldots \mathcal C_m ]$ is kept.  Each cluster is summarized by a sample mean and a count.  To add a new value $x_n$ with a weight $w_n$, the subset of centroids is found that have minimum distance to $x_n$.  This set is reduced by retaining only centroids whose $k$-size after adding $w_n$ would meet the size bound.  If more than one centroid remains, the one with maximum weight is selected.  If an acceptable centroid is found, then the new point, $(x_n,w_n)$, is added to that centroid. If no satisfactory centroid is found, then $(x_n,w_n)$ is used to form a new cluster with weight $w_n$.

Certain insertion orders can cause the number of centroids to increase without bound for this clustering algorithm. For instance, if the values of $X$ are in ascending or descending order, $C$ will contain as many centroids as samples inserted since each incoming sample will never cluster with other samples.  With scale functions other than $k_0$, this happens because each new value of $X$ is always a new maximum (or minimum) and thus will always form a new cluster and that new cluster will have maximum weight of $1$.  With $k_0$, the growth with ordered insertions is slower because as new samples are added to the largest or smallest cluster, that cluster will be allowed to grow to a weight of roughly $n/\delta$, but other clusters will never be merged and thus will stay smaller than desired. This causes the number of clusters to grow as $\Theta(\sqrt n )$.

To avoid this pathological growth, the digest can be consolidated by making a sequential pass over all clusters to merge adjacent clusters whenever the number of clusters grows beyond a preset limit. At worst, then, the clustering variant of the $t$-digest algorithm reduces to the merging variant at the cost of maintaining a more complex data structure such as a balanced tree.

\subsection{Parallel Construction of Digests}
Digests can be constructed separately and merged to construct a digest of a large amount of data. This might be done, for example, in a time-series database where samples are processed at a very high rate. To minimize the amount of data actually stored, digests for each minute of data can be computed and stored. Each day, 1440 minute digests can be combined to form a digest for the day. Each month, the daily digests can be merged to form a monthly digest. At query time, a digest can be formed for any period of time by simply merging a few digests. For example, if we want to compute a digest for the first 100 days of a year, we would merge digests for January, February and March along with either 9 or 10 days from April (depending on whether we have a leap year).

Stratified merging is also be applied when multiple digests are merged after being constructed independently. This is done by simply using a larger value of $\delta$ when constructing the individual digests than is used for the merged result.

\begin{figure*}[htb] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=5in]{figures/combined.pdf}
   \caption{In the left panel, interpolation of the empirical cumulative distribution function between centroids of clusters with more than one sample is done by assuming half of the points for each centroid are to the left of the centroid and half are to the right. In the right panel, special handling for clusters with a single sample is shown. }
   \label{fig:combined}
\end{figure*}

\begin{figure}[h] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=3.in]{figures/error-vs-compression-small.pdf}
   \caption{The scaling of quantile estimation for various values of compression factor $\delta$ and $q$ with $10^6$ samples summarized using $k_2$.
   The general pattern is that absolute error scales like $1/\delta^2$ for small values of $\delta$ and like $1/\sqrt{\delta}$ for values larger than some cutoff. The grey dashed lines provide a reference for $1/\sqrt{\delta}$ scaling, the dotted grey lines show $1/\delta^2$ scaling.   }
   \label{fig:accuracy-scaling}
\end{figure}
\begin{figure}[h] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=3in]{figures/relative-error-one-panel.pdf}
   \caption{Relative error of estimations of quantile with $\delta = 100$ for scale functions $k_1$, $k_2$ and $k_3$. Errors are computed by taking $10^6$ samples from a uniform distribution and comparing estimates from a $t$-digest against exact quantiles computed from the original samples. This was repeated 50 times to get a sense of variability.}
   \label{fig:by-scale}
\end{figure}
\begin{figure}[h] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=3in]{figures/qd-sizes-small.pdf}
   \caption{Absolute error for $t$-digest is much lower than for Q-digest with the same size digest. Here, the compression parameter for each digest was chosen to result in a serialized size of approximately 1kB. Trials with a million samples were repeated 20 times to get an idea of the variability. With this vertical scale, $t$-digest errors are not visibly different from zero.  }
   \label{fig:qd-comparison}
\end{figure}
Figure \ref{fig:merge} illustrates how this turns out. It shows accuracy achieved when summarizing 1,000,000 samples averaged over 20 experiments. The panels, taken from left to right, show the results of merging 5, 20 and 100 sub-digests. Within each panel, the three bars represent the use of a single digest which internally uses $\delta=300,100$ stratified merging, merged digests with $\delta=300$ in the sub-digests and $\delta=100$ in the final result and a non-stratified merge with $\delta=100$ at both levels. At all levels of parallelism, the non-stratified merge result is the worst for accuracy. Stratified parallel merging was comparable to the non-parallel merge though a bit more variable with 5-way parallelism and progressively more accuracy with more parallelism.

In terms of speed, merging $t$-digests is fairly fast relative to practical requirements. In one experiment, 1000 digests were used to summarize 1,000,000 samples each and these digests were then merged into a single digest. It took about 150ms to fill each digest and about 150 ms to merge all thousand digests. Each digest is about 1kB in serialized form in this example so a total of about 1 MB of digests must be processed by the merge. Overall, this means that, with sufficient hardware (roughly 1000 cores), a $t$-digest can be produced from a billion data points in less than half a second. The cost of merging $t$-digests is, nevertheless, higher than the cost of merging some other kinds of sketches such as the moment sketches discussed later.

\subsection{Interpolation}
Accurate interpolation of the empirical distribution function is critical to the accuracy of quantile estimation with the $t$-digest. In general, interpolation proceeds by assuming that half of the mass of any cluster is to the left of the cluster centroid and half is to the right. We also assume that the data between adjacent centroids is uniformly distributed. These assumptions allow us to linearly interpolate the mass of adjacent clusters as is shown in the left panel of Figure \ref{fig:combined}.

Special cases that arise when clusters have only a single sample as is common with the first or last few centroids are shown in the right panel of Figure \ref{fig:combined}. In particular, retaining the minimum and maximum values is equivalent to forcing the first and last clusters to have a single sample.

\section{Size/Accuracy Trade-off}
Not surprisingly, there is a trade-off between the size of the $t$-digest as controlled by the compression parameter $\delta$ versus the accuracy of quantile estimation.  Figure \ref{fig:accuracy-scaling} shows the trade-off for different quantiles with $10^6$ samples from a uniform distribution. The same trade-off applies symmetrically for values of $\delta$ near 1 as well.

As can be seen, the commonly used values of $\delta=100$ or  $\delta=200$ relative accuracy of 10\% or better. With $\delta=200$, relative accuracy is commonly 1\%.

Figure \ref{fig:by-scale} examines the accuracy of quantile estimation with a $t$-digest for different scale functions.  As intended, absolute error in quantile estimation is small and decreases near $q=0$ and $q=1$ (left panel) for scale functions $k_1$, $k_2$ and $k_3$. Though it is hard to see in this figure because of the vertical scale, in the mid-range where $q \in [0.1, 0.9]$, $k_1$ provides somewhat better absolute error than $k_2$ and $k_3$.

All scale functions show a pattern of decreasing absolute error for more and more extreme values of $q$, but $k_2$ and $k_3$ achieve single digit part per million errors for $q\le 0.001$ or $q\ge0.999$, which is surprisingly good since only about 50 to 60 centroids are retained in total for $\delta=100$.

For most applications, we have seen that $\delta=100$ provides sufficient accuracy and scale function $k_2$ or $k_3$ provide a good combination of relative and absolute error. Values as low as $\delta=20$ may be useful, especially if $k_0$ is used to get uniform absolute error. At this level, the persisted size of the digest is about 200 bytes and errors are uniform at about 1\%.

\subsection{Comparison with Q-digest}
In terms of error size, the 4.0 preview implementation of $t$-digest dominates the implementation of the Q-digest from the popular stream-lib package \cite{qdigest,github:stream} when digests of the same size are compared.  This is shown in Figure \ref{fig:qd-comparison}.  In the left panel, the relationship between the compression parameter $q$ and size is shown for both digests for 20 trials where 100,000 uniformly distributed samples are inserted into each kind of digest.  To force the digests to be equal in size, compression parameter values of $\delta_q=20$ for Q-digest  and $\delta_t = 200$ for $t$-digest were chosen. This gives an average digest size of about $874$ bytes for Q-digest and 990 bytes for $t$-digest, as shown in the left panel. The panel on the right compares errors under these conditions and shows that the $t$-digest errors are more than two orders of magnitude smaller for all values of $q$. For values near $q=0$ the $t$-digest produces absolute errors 3-5 orders of magnitude smaller than the Q-digest does. Relative errors are 5 or more orders of magnitude small with the $t$-digest. When compared on distributions with high amounts of skew, the results are even more striking in favor of the $t$-digest because of the limited resolution of the integer data used by the $t$-digest.

Note that the parameters chosen for this comparison depend on the number of samples because with constant $\delta$, the size of the Q-digest increases roughly logarithmically with the number of samples while the size of the $t$-digest is strictly bounded and is nearly constant once the number of samples exceeds $2 \delta$.

\section{Conclusion}
The $t$-digest is a novel on-line sketching algorithm that dominates previous previous sketching algorithms in terms of accuracy and size particularly when considering relative accuracy for extreme quantiles.  The $t$-digest can provide accurate on-line estimates of a variety of of rank-based statistics including quantiles and trimmed mean. The core ideas of the algorithm are simple and the algorithm empirically demonstrates high accuracy even with pathological distributions.  The $t$-digest can also be used in parallel applications or in OLAP-style indexes.

Though not previously described in published literature, the $t$-digest has already been adopted widely by companies such as Facebook, Microsoft and Netflix for internal monitoring and has been included in open source libraries such as Apache Mahout and stream-lib and has been incorporated into prominent open-source projects such as Apache Lucene and Elasticsearch.

\section{Reference Implementation}
The $t$-digest algorithm is available in the form of an open source, well-tested implementation maintained the author \cite{t-digest-project}.  That distribution contains extensive unit and quality tests that exercise the system on a wide variety of distributions, particularly including mixed discrete/continuous distributions, distributions with large offsets and very highly skewed distributions.

Other implementations are available in C++, Go, Python and Javascript.

\section{Acknowledgments}
This paper was prepared with the gracious assistance of Ellen Friedman who reviewed and provided helpful feedback.
%\subsection{}
\bibliographystyle{abbrv}
\bibliography{refs}{}

\end{document}


\section{Natural numbers}


\par
\section{Data Structure}
\label{section:InpMtx:dataStructure}
\par
\par
The {\tt InpMtx} structure has the following fields.
\begin{itemize}
\item
{\tt int coordType} : coordinate type. The following types are
supported.
\begin{itemize}
\item {\tt INPMTX\_BY\_ROWS} --- row triples,
                  the coordinates for $a_{i,j}$ is $(i,j)$.
\item {\tt INPMTX\_BY\_COLUMNS} --- column triples,
                  the coordinates for $a_{i,j}$ is $(j,i)$.
\item {\tt INPMTX\_BY\_CHEVRONS} --- chevron triples,
                  the coordinates for $a_{i,j}$ is $(\min(i,j), j-i)$.
(Chevron $j$ contains $a_{j,j}$, $a_{j,k} \ne 0$ and $a_{k,j} \ne 0$
for $k > j$.)
\item {\tt INPMTX\_CUSTOM} --- custom coordinates.
\end{itemize}
\item
{\tt int storageMode} : mode of storage
\begin{itemize}
\item {\tt INPMTX\_RAW\_DATA} ---
data is raw pairs or triples, two coordinates and (optionally)
one or two double precision values.
\item {\tt INPMTX\_SORTED} --- data is sorted and distinct triples,
                  the primary key is the first coordinate,
                  the secondary key is the second coordinate.
\item {\tt INPMTX\_BY\_VECTORS} --- data is sorted and distinct vectors.
All entries in a vector share something in common.
For example, when {\tt coordType} is {\tt INPMTX\_BY\_ROWS},
{\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS},
row vectors, column vectors, or chevron vectors are stored,
respectively.
When {\tt coordType} is {\tt INPMTX\_CUSTOM},
a custom type, entries in the same
vector have something in common but it need not be a common row,
column or chevron coordinate.
\end{itemize}
\item
{\tt int inputMode} : mode of data input
\begin{itemize}
\item {\tt INPMTX\_INDICES\_ONLY}
--- only indices are stored, not entries.
\item {\tt SPOOLES\_REAL}
--- indices and real entries are stored.
\item {\tt SPOOLES\_COMPLEX}
--- indices and complex entries are stored.
\end{itemize}
\item
{\tt int maxnent} -- present maximum number of entries in the object.
This quantity is initialized by the {\tt InpMtx\_init()} method,
but will be changed as the object resizes itself as necessary.
\item
{\tt int nent} -- present number of entries in the object.
This quantity changes as data is input or when the raw triples are
sorted and compressed.
\item
{\tt double resizeMultiple} -- governs how the workspace grows as
necessary. The default value is 1.25.
\item
{\tt IV ivec1IV} -- an {\tt IV} vector object
of size {\tt mxnent} that holds first coordinates.
\item
{\tt IV ivec2IV} -- an {\tt IV} vector object
of size {\tt mxnent} that holds second coordinates.
\item
{\tt DV dvecDV} -- a {\tt DV} vector object of size {\tt mxnent}
that holds double precision entries. Used only when {\tt inputMode}
is {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}.
\item
{\tt int maxnvector} -- present maximum number of vectors.
This quantity is initialized by the {\tt InpMtx\_init()} method,
but will be changed as the object resizes itself as necessary.
Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}.
\item
{\tt int nvector} -- present number of vectors. Used only when {\tt
storageMode} is {\tt INPMTX\_BY\_VECTORS}.
\item
{\tt IV vecidsIV} -- an {\tt IV} vector object of size {\tt nvector}
to hold the id of each vector.
Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}.
\item
{\tt IV sizesIV} -- an {\tt IV} vector object of size {\tt nvector}
to hold the size of each vector.
Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}.
\item
{\tt IV offsetsIV} -- an {\tt IV} vector object of size {\tt
nvector} to hold the offset of each vector into the {\tt ivec1IV},
{\tt ivec2IV} and {\tt dvecDV} vector objects.
Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}.
\end{itemize}
\par
One can query the attributes of the object with the following
macros.
\begin{itemize}
\item
{\tt INPMTX\_IS\_BY\_ROWS(mtx)} returns {\tt 1} if the entries are
stored by rows, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_BY\_COLUMNS(mtx)} returns {\tt 1} if the entries are
stored by columns, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_BY\_CHEVRONS(mtx)} returns {\tt 1} if the entries are
stored by chevrons, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_BY\_CUSTOM(mtx)} returns {\tt 1} if the entries are
stored by some custom coordinate, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_RAW\_DATA(mtx)} returns {\tt 1} if the entries are
stored as unsorted pairs or triples, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_SORTED(mtx)} returns {\tt 1} if the entries are
stored as sorted pairs or triples, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_BY\_VECTORS(mtx)} returns {\tt 1} if the entries are
stored as vectors, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_INDICES\_ONLY(mtx)} returns {\tt 1} if the entries are
not stored, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_REAL\_ENTRIES(mtx)} returns {\tt 1}
if the entries are real, and {\tt 0} otherwise.
\item
{\tt INPMTX\_IS\_COMPLEX\_ENTRIES(mtx)} returns {\tt 1}
if the entries are complex, and {\tt 0} otherwise.
\end{itemize}


\documentclass[12pt,oneside]{article}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                                %
% The mathematical style of these documents follows                                               %
%                                                                                %
% A. Thompson and B.N. Taylor. The NIST Guide for the Use of the International System of Units.   %
%    NIST Special Publication 881, 2008.                                                          %
%                                                                                %
% http://www.nist.gov/pml/pubs/sp811/index.cfm                                                    %
%                                                                                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\input{../Bibliography/commoncommands}

\usepackage{fancyhdr}
\pagestyle{fancy}
\lhead{}
\rhead{}
\chead{}
\renewcommand{\headrulewidth}{0pt}

\begin{document}

\title{Vulnerability Model Summary - October 1 2014}
\author{DK Ezekoye}

\maketitle

We discussed a simple model for a year one deliverable to exercise the vulnerability framework. The steps that we agreed upon are outlined below.

\section{Target Jurisdiction}

Because of readily available fire data on Arlington, we chose the city/county(?)  of Arlington, VA as our testbed.

\subsection{Required Data}

We will request fire incident data directly from Arlington and also through NFIRS. Having both data sets will be useful in exploring any differences between the local and national data. We also will need census data for demographic data at the tract level.  Housing inventroy data will also be needed at the census tract level.

\section{Ignition Model}

We recognize that fire ignition may or may not trigger fire department response. We choose to analyze the fraction of ignition events that trigger firefighter response. The model to be built on fire ignition will be derived directly from fire incident data sets fit to census tract demograhic and building explanatory variables.  The use of a model form as compared to direct draws from the existing data is motivated by the need to exercise the ignition model under conditions in which the underlying census parameters change in time.  A similar incident ignition model was derived for Austin, TX and was presented to the group.

\section{Fire Model}

A simple fire model of form shown below will be used to drive the fire growth process.  The model is required to include the effects of delays in firefighter response or inadequate firefighter response on increased property loss and damage.  The model is intended to be a simple modification to existing flame spread models that are parameterized using a pyrolysis length. In this case, a pyrolysis area, $A_p$  and burned out area, $A_b$  are to be used.  Sprinkler effects will be modeled into the system as well as firefighter suppression effects.

\begin{equation}
\frac{dA_p}{dt} = \frac{A_f-A_p}{\tau_{ign}} - f(SP,FF,etc.)
\label{eq_AP}
\end{equation}

In the above, the flame area is defined in terms of the difference between the pyrolysis area and the burnout area. An equation is required for the burnout area.Note that modeling of the effects of sprinklers and FF responses are included.

\begin{equation}
\frac{dA_b}{dt} = \frac{A_p-A_b}{\tau_{bo}}
\label{eq_AB}
\end{equation}

In both equations, several calibration parameters are included that will be calibrated using a calibration data set.

\section{FF Response Model}

The efforts of the past study teams in measuring firefighter response times will be used in this model.  We recognize that there are times associated with fire detection, alarm, deployment, travel, and initiation of suppression activities. Some of these times will be held fixed while others, such as travel time will be determined by direct computation of the distance between the specific structure drawn from the population of census tract structures and a responding fire station.  Noise will be added to the travel time to simulate effects of traffic.

\section{Fire Loss}

The response behavior coupled to the fire model provides a damage area estimate for a particular structure.  By smapling over a sufficiently large number of incidents, we will build a histogram/pdf of damage area for the census tract and then for the jurisdiction.  This will be compared to available fire incident data as validation of the model.

\end{document}


\section{Evaluation}
\label{sec:eval}
\begin{table*}[!ht]
\centering
\caption{Time to converged on a solution DSP program for various benchmarks. The programs may not match the known DSP program, but may still be psycho-acoustically equivalent depending on the expertise of the listener. }
\setlength\tabcolsep{2em}
\begin{tabular}{|c | c | c | c |}
 \hline
 Description & True DSP & Synth'ed DSP & Time (sec) \\
 \hline\hline
 Cartoon Spring & $lpf(800)  $ & $lpf(1989) $ & 56.195 \\
 Cartoon Spring & $lpf(5000) $ & $lpf(4000) \arrComp hpf(7000) $ & 54.004 \\
 Cartoon Spring & $hpf(1500) $ & $lpf(1000) \arrComp hpf(1000) $ & 53.964 \\
 BTS DNA (Kpop) & $lpf(2000) $ & $lpf(1996)	 $ & 56.874 \\
 Holst Mars     & $hpf(3500) $ & $lpf(10000) \arrComp hpf(1000)$  & 55.444 \\
 \hline
\end{tabular}
\label{table:eval}
\end{table*}

We implemented a DSP-PBE tool based on the approach described in Section~\ref{sec:distance} and Section~\ref{sec:search}.
Our tool is available open-source at~\url{www.github.com/santolucito/DSP-PBE}\footnote{The exact version of the code used for this evaluation is available at commit \url{https://github.com/santolucito/DSP-PBE/tree/d022954164b830395bddb21cdc94046ed6882083}.}.
Our tool is mostly written in Haskell and uses the Vivid library~\cite{vivid} for bindings to SuperCollider~\cite{supercollider}.
Haskell allows easy access to type information and metaprogram construction tools that are useful for program synthesis, however the programs themselves are easily translated back to SuperCollider ``synth defs'', which are DSP filter programs.
We use the scipy python module for calling the FFT since the library is quite mature and provides a simplified interface specifically for calling FFT on audio.

One key implementation point is that we use a separate representation of a DSP for running gradient descent, and for actually processing the audio.
Gradient descent works best when all parameters are in the same scale, so we map the frequencies [0,20k] Hz to a [-1,1] scale.
Likewise, we map the application levels for each filter (how much of the filtered output should be included in the final mix) on a [-1,1] scale.

In Table~\ref{table:eval}, we show the results of running our tool on a set of benchmarks of input/output example audio samples.
The audio samples were transformed in Audacity, using the Low Pass Filter and High Pass Filter effects.
Since we use SuperCollider's filter implementations on the backend, there may be very slight variation, but this is to be expected in real-world application as well.
All experiments were run on an Intel Core i7-6820HQ CPU @ 2.70GHz with 16 GB of RAM and an Intel Sunrise Point-H HD Audio sound card.

We can also breakdown the runtime cost of synthesis into the two different stages - 1) initial program selection, and 2) gradient descent.
The initial program selection phase is a mostly fixed cost, as we always evaluate the same distribution of initial value.
On average this process takes roughly 40 seconds.
We outline future directions of research that may be able to reduce this cost in Section~\ref{sec:rtypes}.


\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{bm}
\usepackage[a4paper, inner=2.5cm, outer=2.5cm, top=2.5cm, bottom=2.5cm]{geometry}
\usepackage{graphicx}
\graphicspath{{figures/}}

\title{Classical Laminate Theory}
\author{Andy Perez}
\date{February 2019}

\begin{document}
\setlength{\parindent}{0cm}
\renewcommand{\thefootnote}{\roman{footnote}}

\maketitle

This document provides a summarized walk-through of Classical Laminate Theory (CLT) using NASA Reference Publication 1351 \textit{Basic Mechanics of Laminate Composite Plates} \cite{nasa} as a reference. Supplemental and original source information is also found in Jones' \textit{Mechanics of Composite Materials} \cite{jones}

\section{Lamina Properties}
\label{sec:lamina_properties}
Basic material properties are determined empirically, and must be known in order to determine the lamnia's characteristic matrices and the resulting loads and stresses. These values are:
  \begin{center}
    \begin{table}[h!]
      \centering
      \label{tbl:lamprop}
      \vspace{1mm}
      \begin{tabular}{cl}
        Symbol & Description \\
        \hline \hline
        $\bm{E_{11}}$ & elastic modulus in the ply's 0$^{\circ}$-direction \\
        $\bm{E_{22}}$ & elastic modulus in the ply's 90$^{\circ}$-direction \\
        $\bm{\nu_{12}}$ & Poisson's ratio in the $2$-direction when the lamina is loaded in the $1$-direction \\
        $\bm{G_{12}}$ & Shear modulus in the $12$-plane \\
        $\bm{t_{k}}$ & thickness of the lamina \\
        $\bm{\alpha_{11}}$ & thermal expansion coefficient in the in the ply's 0$^{\circ}$-direction \\
        $\bm{\alpha_{12}}$ & thermal expansion coefficient in the in the ply's 90$^{\circ}$-direction \\
        $\bm{\beta_{11}}$ & hygral expansion coefficient in the in the ply's 0$^{\circ}$-direction \\
        $\bm{\beta_{12}}$ & hygral expansion coefficient in the in the ply's 90$^{\circ}$-direction \\
        $\bm{\theta}$ & the ply orientation (used for off-axis transformations)
      \end{tabular}
    \end{table}
  \end{center}

\section{Characteristic Matrices of the Lamina}
\label{sec:lamina_matrices}
Note that, in general, the subscript $k$ is used to denote that the a value is a lamina value. The characteristic matrices for each lamina can be calculated as follows:

  \begin{enumerate}
    \item The \emph{reduced stiffness matrix} $\bm{Q_{k}}$ describes the elastic behavior of the ply in in-plane loading.\footnote{$Q_{k}$ is derived from Staab \cite{staab}, Eq. 3.9, while the values for $Q_{11}$, $Q_{22}$, and $Q_{12}$ are from Nettles \cite{nasa}, Eq. (10).}
      \begin{equation}
        \label{var:Qk} % Staab Eq. 3.9
        \bm{Q_{k}} = \left[
                        \begin{array}{ccc}
                          Q_{11} & Q_{12} & 0 \\
                          Q_{12} & Q_{22} & 0 \\
                          0  &      0     & Q_{66}
                        \end{array}
                      \right]
      \end{equation}
      where
      $$
        Q_{11} = \frac{E_{11}^{2}}{\left(E_{11} - \nu_{12} \cdot E_{22}\right)}
      $$ \vspace{1mm}
      $$
        Q_{22} = \frac{E_{11} E_{22}}{\left(E_{11} - \nu_{12}^2 E_{22}\right)}
      $$ \vspace{1mm}
      $$
      Q_{12} = \frac{\nu_{12} E_{11} E_{22}}{\left(E_{11} - \nu_{12}^2 E_{22}\right)}
      $$ \vspace{1mm}
      $$
        Q_{66} = G_{12}
      $$
    \item The \emph{strain transformation matrix} $\bm{T_{\varepsilon}}$ is used to transform other characteristic matrices into the laminate coordinate system.\footnote{Staab \cite{staab}, Eq 2.1}
    \begin{equation}
      \label{var:Tepsilon} % Staab Eq. 2.1
      \bm{T_{\varepsilon}} = \left[ \begin{array}{ccc}
                                      m^{2} & n^{2} & mn \\
                                      n^{2} & m^{2} & -mn \\
                                      -2mn & 2mn & m^{2} - n^{2} \\
                                    \end{array}
                             \right]
    \end{equation}
    where
    $$m=\cos\theta$$
    $$n=\sin\theta$$
    $\theta$ is the relative orientation of the lamina with respect to the laminate coordinate system shown in Figure~\ref{fig:ply_axes}\footnote{\emph{ibid.}, Fig. 3.3}.
    \begin{figure}[h] % Staab Figure 3.3
      \centering
      \includegraphics[scale=.25]{staab_fig_3-3.png}
      \caption{On- and Off-axis Ply Orientations}
      \label{fig:ply_axes}
    \end{figure}

  \item The \emph{stress transformation matrix} $\bm{T_{\sigma}}$, by comparison, is calculated by the following equation.\footnote{\emph{ibid.}, Eq. 2.3}
    \begin{equation}
      \label{var:Tsigma}
      \bm{T_{\sigma}} = \left[
                          \begin{array}{ccc}
                            m^{2} & n^{2} & 2mn \\
                            n^{2} & m^{2} & -2mn \\
                            -mn & mn & m^{2} - n^{2} \\
                          \end{array}
                        \right]
    \end{equation}
    It should be noted that if tensor notation is used for both strains, then the stress and strain transformation matrices should be equal, $\bm{T_{\varepsilon}} = \bm{T_{\sigma}}$.

  \item The \emph{transformed reduced stiffness matrix} $\bm{\overline{Q}_{k}}$ is calculated by modifying $Q_{k}$ by $T_{\varepsilon}$ \footnote{\emph{ibid.} Section 3.2.2}.
    \begin{equation}
      \label{var:Qbar}
      \bm{\overline{Q}_{k}} = \bm{T_{\sigma}}^{-1} \bm{Q_{k}} \bm{T_{\varepsilon}}
    \end{equation}

  \end{enumerate}

\section{Determining the $\bm{A}$, $\bm{B}$, and $\bm{D}$ Matrices}
When lamina are bonded together to form a laminate, there exist three matrices that characterize the stiffness of the laminate. These are the \emph{extensional stiffness matrix} $\bm{A}$, the \emph{extension-bending stiffness matrix} $\bm{B}$, and the \emph{bending stiffness matrix} $\bm{D}$.
  \subsection{The Extensional Stiffness Matrix}
  The \emph{extensional stiffness matrix} $\bm{A}$ characterizes the axial, in-plane stiffness of the laminate and is defined
  \begin{equation}
    \bm{A} = \left[ \begin{array}{ccc}
               A_{11} & A_{12} & A_{16} \\
               A_{12} & A_{22} & A_{26} \\
               A_{16} & A_{26} & A_{16} \\
             \end{array} \right]
  \end{equation}
  where
  \begin{equation}
    A_{ij} = \sum_{k=1}^{n}\big[\overline{Q}_{ij}\big]_{k}\big(z_{k} - z_{k-1}\big)
  \end{equation}

  \subsection{The Extension-Bending Coupling Matrix}
  The \emph{extension-bending coupling matrix} $\bm{B}$ couples the extensional stiffness and the bending stiffness matrices. It is defined:
  \begin{equation}
    \bm{B} = \left[ \begin{array}{ccc}
               B_{11} & B_{12} & B_{16} \\
               B_{12} & B_{22} & B_{26} \\
               B_{16} & B_{26} & B_{16} \\
             \end{array} \right]
  \end{equation}
  where
  \begin{equation}
    B_{ij} = \frac{1}{2}\sum_{k=1}^{n}\big[\overline{Q}_{ij}\big]_{k}\big(z_{k}^{2} - z_{k-1}^{2}\big)
  \end{equation}

  \subsection{The Bending Stiffness Matrix}
  The \emph{bending stiffness matrix} $\bm{B}$ characterizes the stiffness of the laminate when subjected to bending loads and is defined:
  \begin{equation}
    \bm{D} = \left[ \begin{array}{ccc}
               D_{11} & D_{12} & D_{16} \\
               D_{12} & D_{22} & D_{26} \\
               D_{16} & D_{26} & D_{16} \\
             \end{array} \right]
  \end{equation}
  where
  \begin{equation}
    D_{ij} = \frac{1}{3}\sum_{k=1}^{n}\big[\overline{Q}_{ij}\big]_{k}\big(z_{k}^{3} - z_{k-1}^{3}\big)
  \end{equation}

  \subsection{The $\bm{ABD}$ Matrix}
  Together, all three stiffness matrices fully characterize the laminate stiffness and can be used to relate applied loads to the resulting strains on a laminate and in its lamina. This relationship is defined as
    \begin{equation}
      \left\{\begin{array}{c} \bm{N} \\ \hline \bm{M} \end{array} \right\} = \left[\begin{array}{c|c} \bm{A} & \bm{B} \\ \hline \bm{B} & \bm{D} \end{array} \right] \left\{ \begin{array}{c} \bm{\varepsilon^{0}} \\ \hline \bm{\kappa} \end{array} \right\}
    \end{equation}
  which, when expanded, becomes
  \begin{equation}
      \left\{\begin{array}{c} N_{xx}'\\
                             N_{yy}'\\
                             N_{xy}'\\
                             \hline
                             M_{xx}'\\
                             M_{yy}'\\
                             M_{xy}'\\
      \end{array} \right\} =
      \left[ \begin{array}{ccc|ccc} A_{11} & A_{12} & A_{16} & B_{11} & B_{12} & B_{16} \\
                                  A_{21} & A_{22} & A_{26} & B_{21} & B_{22} & B_{26} \\
                                  A_{61} & A_{62} & A_{66} & B_{61} & B_{62} & B_{66} \\
                                  \hline
                                  B_{11} & B_{12} & B_{16} & D_{11} & D_{12} & D_{16} \\
                                  B_{21} & B_{22} & B_{26} & D_{21} & D_{22} & D_{26} \\
                                  B_{61} & B_{62} & B_{66} & D_{61} & D_{62} & D_{66} \\
              \end{array} \right]
      \left\{ \begin{array}{c} \varepsilon_{xx}^{0} \\ \varepsilon_{yy}^{0} \\ \gamma_{xy}^{0} \\ \hline \kappa_{xx} \\ \kappa_{yy} \\ \kappa_{xy} \end{array}\right\}
  \end{equation}

\bibliographystyle{ieeetr}
\bibliography{clt}

\section{Creating the ABD Matrix}
The ABD matrix is a 6x6 matrix that serves as a connection between the applied loads and the associated strains in the laminate. It essentially defines the elastic properties of the entire laminate. To assemble the ABD matrix, follow these steps:

\begin{enumerate}
    \item Calculate reduced stiffness matrix $\bm{Q_{k}}$ for each material used in the laminate (if a laminate uses only one type of composite material, there will be only 1 stiffness matrix). The stiffness matrix describes the elastic behavior of the ply in plane loading

    \begin{equation}
        \bm{Q_{k}} = \left[ \begin{array}{ccc}
                                Q_{11} & Q_{12} & 0 \\
                                Q_{21} & Q_{22} & 0 \\
                                0  &      0     & Q_{66}
                            \end{array} \right]
    \end{equation}
    where

    $$
        Q_{11} = \frac{E_{11}^{2}}{\left(E_{11} - \nu_{12} \cdot E_{22}\right)}
    $$ \vspace{1mm}
    $$
        Q_{12} = \frac{\nu_{12} E_{11} E_{22}}{\left(E_{11} - \nu_{12}^2 E_{22}\right)}
    $$ \vspace{1mm}
    $$
        Q_{22} = \frac{E_{11} E_{22}}{\left(E_{11} - \nu_{12}^2 E_{22}\right)}
    $$ \vspace{1mm}
    $$
        Q_{66} = G_{12}
    $$

    where

    $$
        Q_{11} = \frac{E_{11}^{2}}{\left(E_{11} - \nu_{12} \cdot E_{22}\right)}
    $$ \vspace{1mm}
    $$
        Q_{12} = \frac{\nu_{12} E_{11} E_{22}}{\left(E_{11} - \nu_{12}^2 E_{22}\right)}
    $$ \vspace{1mm}
    $$
        Q_{22} = \frac{E_{11} E_{22}}{\left(E_{11} - \nu_{12}^2 E_{22}\right)}
    $$ \vspace{1mm}
    $$
        Q_{66} = G_{12}
    $$

    \item Calculate the transformed reduced stiffness matrix $\bm{\overline{Q_{k}}}$ for each ply based on the reduced stiffness matrix and fiber angle.
    \begin{equation}
        \bm{\overline{Q}_{k}} =
        \left[ \begin{array}{ccc}
            \overline{Q}_{11} & \overline{Q}_{12} & \overline{Q}_{16} \\
            \overline{Q}_{21} & \overline{Q}_{22} & \overline{Q}_{26} \\
            \overline{Q}_{61} & \overline{Q}_{62} & \overline{Q}_{66}
        \end{array} \right]
    \end{equation}

    where \\
    $$
        \overline{Q}_{11} = Q_{11}\cos^{4}(\theta) + 2\big(Q_{12} + Q_{66}\big)\cos^{2}(\theta)\cdot\sin^{2}(\theta) + Q_{22}\sin^{4}(\theta)
    $$
    $$
        \overline{Q}_{12} = \overline{Q}_{21} = Q_{12}\big(\cos^{4}(\theta) + \sin^{4}(\theta)\big) + \big(Q_{11} + Q_{22} - 4Q_{66}\big)\cos^{2}(\theta)\sin^{2}(\theta)
    $$
    $$
        \overline{Q}_{16} = \overline{Q}_{61} = \big(Q_{11} - Q_{12} - 2Q_{66}\big)\cos^{3}(\theta)\sin(\theta) - \big(Q_{22} - Q_{12} - 2Q_{66}\big)\cos(\theta)\sin^{3}(\theta)
    $$
    $$
        \overline{Q}_{22} = Q_{11}\sin^{4}(\theta) + 2\big(Q_{12} + Q_{66}\big)\cos^{2}(\theta)\cdot\sin^{2}(\theta) + Q_{22}\cos^{4}(\theta)
    $$
    $$
        \overline{Q}_{26} = \overline{Q}_{62} = \big(Q_{11} - Q_{12} - 2Q_{66}\big)\cos(\theta)\sin^{3}(\theta) - \big(Q_{22} - Q_{12} - 2Q_{66}\big)\cos^{3}(\theta)\sin(\theta)
    $$
    $$
        \overline{Q}_{66} = \big(Q_{11} + Q_{22} - 2Q_{12} - 2Q_{66}\big)\cos^{2}(\theta)\sin^{2}(\theta) + Q_{66}\big(\cos^{4}(\theta) + \sin^{4}(\theta)\big)
    $$

    \item Calculate the laminate \emph{extensional stiffness matrix}, $\bm{A}$:
    \begin{equation}
    \bm{A} = \left[\begin{array}{ccc} A_{11} & A_{12} & A_{16} \\ A_{21} & A_{22} & A_{26} \\ A_{61} & A_{62} & A_{66}\end{array}\right]
    \end{equation}
    The individual terms of $\bm{A}$ are calculated by
    \begin{equation}
        A_{ij} = \sum_{k=1}^{n} \big\{Q_{ij}\big\}_{n} \left(z_{k} - z_{k-1}\right)
    \end{equation}
    where $z$ is the vertical position in the ply from the midplane, and $k$ is for each ply.

    \item Calculate the laminate \emph{coupling stiffness matrix}, $\bm{B}$:
    \begin{equation}
        \left[\begin{array}{ccc} B_{11} & B_{12} & B_{16} \\ B_{21} & B_{22} & B_{26} \\ B_{61} & B_{62} & B_{66}\end{array}\right]
    \end{equation}
    where
    \begin{equation}
        B_{ij} = \frac{1}{2} \sum_{k=1}^{n} \big\{Q_{ij}\big\}_{n} \left(z_{k}^{2} - z_{k-1}^{2}\right)
    \end{equation}

    \item Calculate the laminate \emph{bending stiffness matrix}, $\bm{D_{ij}}$:
    \begin{equation}
        \left[\begin{array}{ccc} D_{11} & D_{12} & D_{16} \\ D_{21} & D_{22} & D_{26} \\ D_{61} & D_{62} & D_{66}\end{array}\right]
    \end{equation}
    where
    \begin{equation}
        D_{ij} = \frac{1}{3} \sum_{k=1}^{n} \big\{Q_{ij}\big\}_{n} \left(z_{k}^{3} - z_{k-1}^{3}\right)
    \end{equation}

    \item Assemble the $\bm{ABD}$ matrix:
    \begin{equation}
        \bm{ABD} = \left[\begin{array}{c|c}
            \bm{A} & \bm{B} \\
            \hline
            \bm{B} & \bm{D}
        \end{array} \right]
    \end{equation}
    \end{enumerate}

\section{Laminate Properties}
Overall laminate properties can be calculated from the $\bm{ABD}$ matrix.
\begin{equation}
    \left\{\begin{array}{c} \bm{N} \\ \hline \bm{M} \end{array} \right\} = \left[\begin{array}{c|c} \bm{A} & \bm{B} \\ \hline \bm{B} & \bm{D} \end{array} \right] \left\{ \begin{array}{c} \bm{\varepsilon^{0}} \\ \hline \bm{\kappa} \end{array} \right\}
\end{equation}

\begin{equation}
    \left\{ \begin{array}{c} Q_{x} \\ Q_{y} \end{array} \right\} =
    \left[ \begin{array}{cc} A_{55} & A_{45} \\ A_{45} & A_{44} \end{array} \right]_{k}
    \left\{ \begin{array}{c} \gamma_{xz} \\ \gamma_{yz} \end{array} \right\}_{k}
\end{equation}
where
\begin{equation}
    A_{ij} = c \sum_{k=1}^{N} \left[ \overline{Q}_{ij} \right]_{k} \left\{ \big(z_{k} - z_{k-1} \big) - \frac{4}{3h^{2}} \big(z_{k}^3 - z_{k-1}^3 \big) \right\}
\end{equation}
where $i,j=4,5$ and $c=6/5$ for a rectangular section. Generally speaking, the stiffness terms ($\overline{Q}_{44}$, $\overline{Q}_{55}$, etc.) associated with $Q_{x}$ and $Q_{y}$ are difficult to experimentally determine and are, therefore, approximated.

\begin{equation}
    \left\{\begin{array}{c} N_{xx}'\\
                           N_{yy}'\\
                           N_{xy}'\\
                           \hline
                           M_{xx}'\\
                           M_{yy}'\\
                           M_{xy}'\\
    \end{array} \right\} =
    \left[ \begin{array}{ccc|ccc} A_{11} & A_{12} & A_{16} & B_{11} & B_{12} & B_{16} \\
                                A_{21} & A_{22} & A_{26} & B_{21} & B_{22} & B_{26} \\
                                A_{61} & A_{62} & A_{66} & B_{61} & B_{62} & B_{66} \\
                                \hline
                                B_{11} & B_{12} & B_{16} & D_{11} & D_{12} & D_{16} \\
                                B_{21} & B_{22} & B_{26} & D_{21} & D_{22} & D_{26} \\
                                B_{61} & B_{62} & B_{66} & D_{61} & D_{62} & D_{66} \\
            \end{array} \right]
    \left\{ \begin{array}{c} \varepsilon_{xx}^{0} \\ \varepsilon_{yy}^{0} \\ \gamma_{xy}^{0} \\ \hline \kappa_{xx} \\ \kappa_{yy} \\ \kappa_{xy} \end{array}\right\}
\end{equation}
where $N'$ and $M'$ are the total running loads, including thermal and hygral effects:
\begin{equation}
    N_{ij}' = N_{ij} + N_{ij}^T + N_{ij}^M
\end{equation}
\begin{equation}
    M_{ij}' = M_{ij} + M_{ij}^T + M_{ij}^M
\end{equation}

\section{Calculating Individual Ply Strains and Stresses}
Having calculated the $\bm{ABD}$ matrix for the laminate, it is possible to then calculate individual ply strains and stresses based on the loads and temperature applied to the laminate.
\begin{enumerate}
    \item Calculate the thermal expansion coefficients for each ply:
    \begin{equation}
        \alpha_{xx} = \alpha_{11} \cos^{2}(\theta) + \alpha_{22} \sin^{2}(\theta)
    \end{equation}
    \begin{equation}
        \alpha_{yy} = \alpha_{11} \sin^{2}(\theta) + \alpha_{22} \cos^{2}(\theta)
    \end{equation}
    \begin{equation}
        \alpha_{xy} = 2\cos(\theta)\sin(\theta)\big(\alpha_{11} - \alpha_{22})
    \end{equation}

    \item Calculate the hygral expansion coefficients for each ply:
    \begin{equation}
        \beta_{xx} = \beta_{11} \cos^{2}(\theta) + \beta_{22} \sin^{2}(\theta)
    \end{equation}
    \begin{equation}
        \beta_{yy} = \beta_{11} \sin^{2}(\theta) + \beta_{22} \cos^{2}(\theta)
    \end{equation}
    \begin{equation}
        \beta_{xy} = 2\cos(\theta)\sin(\theta)\big(\beta_{11} - \beta_{22})
    \end{equation}

    \item Calculate the thermal running loads:
    \begin{equation}
        N_{xx}^{T} = \Delta T \sum_{k=1}^{n} \Big\{\big[\overline{Q_{11}}\alpha_{xx} + \overline{Q_{12}}\alpha_{yy} + \overline{Q_{16}}\alpha_{xy}\big]_{k}\big(z_{k} - z_{k-1}\big)\Big\}
    \end{equation}
    \begin{equation}
        N_{yy}^{T} = \Delta T \sum_{k=1}^{n} \Big\{\big[\overline{Q_{12}}\alpha_{xx} + \overline{Q_{22}}\alpha_{yy} + \overline{Q_{26}}\alpha_{xy}\big]_{k}\big(z_{k} - z_{k-1}\big)\Big\}
    \end{equation}
    \begin{equation}
        N_{xy}^{T} = \Delta T \sum_{k=1}^{n} \Big\{\big[\overline{Q_{16}}\alpha_{xx} + \overline{Q_{26}}\alpha_{yy} + \overline{Q_{66}}\alpha_{xy}\big]_{k}\big(z_{k} - z_{k-1}\big)\Big\}
    \end{equation}

    \begin{equation}
        M_{xx}^{T} = \frac{\Delta T}{2} \sum_{k=1}^{n} \Big\{\big[\overline{Q_{11}}\alpha_{xx} + \overline{Q_{12}}\alpha_{yy} + \overline{Q_{16}}\alpha_{xy}\big]_{k}\big(z_{k}^{2} - z_{k-1}^{2}\big)\Big\}
    \end{equation}
    \begin{equation}
        M_{yy}^{T} = \frac{\Delta T}{2} \sum_{k=1}^{n} \Big\{\big[\overline{Q_{12}}\alpha_{xx} + \overline{Q_{22}}\alpha_{yy} + \overline{Q_{26}}\alpha_{xy}\big]_{k}\big(z_{k}^{2} - z_{k-1}^{2}\big)\Big\}
    \end{equation}
    \begin{equation}
        M_{xy}^{T} = \frac{\Delta T}{2} \sum_{k=1}^{n} \Big\{\big[\overline{Q_{16}}\alpha_{xx} + \overline{Q_{26}}\alpha_{yy} + \overline{Q_{66}}\alpha_{xy}\big]_{k}\big(z_{k}^{2} - z_{k-1}^{2}\big)\Big\}
    \end{equation}

    \item Calculate the hygral expansion running loads:
    \begin{equation}
        N_{xx}^{M} = \Delta T \sum_{k=1}^{n} \Big\{\big[\overline{Q_{11}}\beta_{xx} + \overline{Q_{12}}\beta_{yy} + \overline{Q_{16}}\beta_{xy}\big]_{k}\big(z_{k} - z_{k-1}\big)\Big\}
    \end{equation}
    \begin{equation}
        N_{yy}^{M} = \Delta T \sum_{k=1}^{n} \Big\{\big[\overline{Q_{12}}\beta_{xx} + \overline{Q_{22}}\beta_{yy} + \overline{Q_{26}}\beta_{xy}\big]_{k}\big(z_{k} - z_{k-1}\big)\Big\}
    \end{equation}
    \begin{equation}
        N_{xy}^{M} = \Delta T \sum_{k=1}^{n} \Big\{\big[\overline{Q_{16}}\beta_{xx} + \overline{Q_{26}}\beta_{yy} + \overline{Q_{66}}\beta_{xy}\big]_{k}\big(z_{k} - z_{k-1}\big)\Big\}
    \end{equation}

    \begin{equation}
        M_{xx}^{M} = \frac{\Delta T}{2} \sum_{k=1}^{n} \Big\{\big[\overline{Q_{11}}\beta_{xx} + \overline{Q_{12}}\beta_{yy} + \overline{Q_{16}}\beta_{xy}\big]_{k}\big(z_{k}^{2} - z_{k-1}^{2}\big)\Big\}
    \end{equation}
    \begin{equation}
        M_{yy}^{M} = \frac{\Delta T}{2} \sum_{k=1}^{n} \Big\{\big[\overline{Q_{12}}\beta_{xx} + \overline{Q_{22}}\beta_{yy} + \overline{Q_{26}}\beta_{xy}\big]_{k}\big(z_{k}^{2} - z_{k-1}^{2}\big)\Big\}
    \end{equation}
    \begin{equation}
        M_{xy}^{M} = \frac{\Delta T}{2} \sum_{k=1}^{n} \Big\{\big[\overline{Q_{16}}\beta_{xx} + \overline{Q_{26}}\beta_{yy} + \overline{Q_{66}}\beta_{xy}\big]_{k}\big(z_{k}^{2} - z_{k-1}^{2}\big)\Big\}
    \end{equation}

    \item Calculate the inverse $\bm{ABD}$ matrix, $\bm{abd}$:
    \begin{equation}
        \bm{abd} = \left\{ \begin{array}{c|c} \bm{A^{-1}} & \bm{B^{-1}} \\ \hline \bm{B^{-1}} & \bm{D^{-1}} \end{array} \right\}
    \end{equation}
    This inverse matrix is the \emph{stiffness matrix} of the laminate.

    \item Calculate midplane strains and curvatures induced in the laminate using the relationship between strain, stiffness, and the applied load.
    \begin{equation}
        \bm{\varepsilon} = \bm{abd}\cdot\bm{N}
    \end{equation}
    Expanded, this equation becomes:
    $$
        \left[\begin{array}{c} \varepsilon_{xx}^{0} \\ \varepsilon_{yy}^{0} \\ \gamma_{xy}^{0} \\ \hline \kappa_{xx} \\ \kappa_{yy} \\ \kappa_{xy} \end{array}\right] =
        \left[\begin{array}{ccc|ccc} a_{11} & a_{12} & a_{16} & b_{11} & b_{12} & b_{16} \\
                                    a_{21} & a_{22} & a_{26} & b_{21} & b_{22} & b_{26} \\
                                    a_{61} & a_{62} & a_{66} & b_{61} & b_{62} & b_{66} \\
                                    \hline
                                    b_{11} & b_{12} & b_{16} & d_{11} & d_{12} & d_{16} \\
                                    b_{21} & b_{22} & b_{26} & d_{21} & d_{22} & d_{26} \\
                                    b_{61} & b_{62} & b_{66} & d_{61} & d_{62} & d_{66} \\\end{array}\right] \cdot
        \left[\begin{array}{c} N_{xx} + N_{xx}^T + N_{xx}^M \\
                               N_{yy} + N_{yy}^T + N_{yy}^M \\
                               N_{xy} + N_{xy}^T + N_{xy}^M \\
                               \hline
                               M_{xx} + M_{xx}^T + M_{xx}^M \\
                               M_{yy} + M_{yy}^T + M_{yy}^M \\
                               M_{xy} + M_{xy}^T + M_{xy}^M \\
        \end{array}\right]
    $$

    \item Individual ply strains are then calculated in the laminate $xy$-coordinate system by the equation:
    \begin{equation}
        \left\{\begin{array}{c}
            \varepsilon_{xx} \\
            \varepsilon_{yy} \\
            \gamma_{xy}
        \end{array}\right\} =
        \left\{\begin{array}{c}
            \varepsilon_{xx}^{0} \\
            \varepsilon_{xy}^{0} \\
            \gamma_{xy}^{0}
        \end{array}\right\} +
        z \left\{\begin{array}{c}
            \kappa_{xx} \\
            \kappa_{yy} \\
            \kappa_{xy}
        \end{array}\right\}
    \end{equation}

    \item Individual ply stresses are similarly calculated in the $xy$-coordinate system by the corresponding equation:
    \begin{equation}
        \left[\begin{array}{c}
            \sigma_{xx} \\
            \sigma_{yy} \\
            \tau_{xy}
        \end{array}\right] =
        \left[ \begin{array}{ccc} \overline{Q}_{11} & \overline{Q}_{12} & \overline{Q}_{16} \\
                                  \overline{Q}_{21} & \overline{Q}_{22} & \overline{Q}_{26} \\
                                  \overline{Q}_{61} & \overline{Q}_{62} & \overline{Q}_{66}
        \end{array} \right] \cdot
        \left\{\begin{array}{c}
            \varepsilon_{xx} - \Delta T \alpha_{xx} - \Delta T \beta_{xx}\\
            \varepsilon_{yy} - \Delta T \alpha_{yy} - \Delta T \beta_{yy}\\
            \gamma_{xy} - \Delta T \alpha_{xy} - \Delta T \beta_{xy}
        \end{array}\right\}
    \end{equation}

    \item Interlaminar shear forces on each ply are calculated

\end{enumerate}

\end{document}

docs/ref/Classical Laminate Theory/Classical Laminate Theory.tex


% !TEX root=/home/tavant/these/manuscript/src/manuscript.tex

\section{Solving the kinetic \acs{DR} for general distribution functions}
  \label{sec-DR-solver}
  % \renewcommand\rightmark{\expandafter\MakeUppercase{Solver for the general DR}}

  In order to solve the \ac{DR}  $\hat\epsilon(\vect{k}, \omega) = 0$ of \cref{eq-drECDI}, we solve for every $\vect{k}$ the complex value of $\omega$ that is a zero, also named a root, of $\hat\epsilon(\vect{k}, \omega)$.
  Hence, we first need to evaluate $\hat\epsilon(\vect{k}, \omega)$ for any given arguments $\vect{k}, \omega$.
  Then, we can find the root.

  \subsection{Numerical determination of \texorpdfstring{$\hat\epsilon$}{the plasma dielectric function.}} \label{subsec-numepsilon}

  The calculation of $Z$, needed to determine $\hat{\epsilon}$, is usually done using the Maxwellian hypothesis \citep{cavalier2013} (hence using the Fried and Compte function $Z_M$), the kappa distribution \citep{ziebell2017}, or other analytic expressions.
  We can also use a linear combination of such simple distribution functions, such as done in the software WHAMP in \citet{ronnmark1982}.
  Here we propose to solve the dispersion relation $\hat{\epsilon}=0$ using the distribution function measured in the \ac{PIC} simulation.

  The numerical computation of $\norm{\hat\epsilon}$ is done using the method of \citet{xie2013} for computing $\tilde{Z}$ the numerical approximation of $Z$.
  It uses the fact that $Z$ is an Hilbert transform of the distribution function, and that the Hilbert transform can be changed to a Fourier Transform, weighted by well chosen basis functions, so the \ac{FFT} algorithm can be used \citep{weideman1995}.
  An interesting point is that the evaluation of $\tilde{Z}(\eta)$ is done by a polynomial function, which coefficients depend only on the distribution function $f$.
  Hence, they need to be determined only once, and evaluating $\tilde{Z}(\eta)$ is relatively fast.

  \begin{figure}[!hbt]
    \centering
    \includegraphics[width=0.8\textwidth]{Validation_numericalZ.pdf}
    \caption{Comparison of the numerical evaluation of $\tilde{Z}_M(\eta)$ for a Maxwellian distribution function with the Fried and Conte function (from the \texttt{plasmapy} python package) for different values of the imaginary part of $\eta: 5, 0,-1,$ and $-2.2$.  }
    \label{fig-numZ}
  \end{figure}
  \cref{fig-numZ} shows the comparison of the numerical evaluation of $\tilde{Z}(\eta)$ for a Maxwellian distribution function with the Fried and Conte function (from the \texttt{plasmapy} python package) for different values of the imaginary part of $\eta$.
  We can see that for ${\rm Im}(\eta)$ positive, null or slightly negative, the two functions gives exactly the same results.
  However, for larger negative values of ${\rm Im}(\eta)$, the two functions gives different results.

  This discrepancy between $Z_M$ and $\tilde{Z}_M$ for large negative imaginary argument is certainly due to the fact that the analytic expansion of $Z$ to the complex plane require the evaluation of the distribution function for complex velocities \citep{xie2013,weideman1995}.
  However, the discrete velocity distribution function measured in the \ac{PIC} simulation cannot be properly evaluated for complex velocities.
  On the other hand, we are only interested in instabilities, with positive growth rate.
  Hence, the discrepancy observed should not affect the conclusions of the study.

  \begin{figure}[hbt]
    \centering
    \includegraphics[width=0.8\textwidth]{Validation_numericalZ_bis.png}
    \caption{Comparison of the numerical evaluation of $\hat\epsilon$ from \cref{eq-drECDI} for a Maxwellian distribution function with (left) the Fried and Conte function (from the \texttt{plasmapy} python package) and (right) the numerical $\tilde{Z}$, in logarithmic scale.  }
    \label{fig-numZbis}
  \end{figure}

  \Cref{fig-numZbis} presents the comparison of the calculation of $\hat\epsilon$ from \cref{eq-drECDI} for a Maxwellian distribution function with (left) the Fried and Conte function (from the `plasmapy` python package) and (right) the numerical $\tilde{Z}$.
  We can see that the root with the greater imaginary part, located close to (0.2, 0), is the same in both cases, but that other roots for large negative imaginary part are not similar.
  But as said previously, these roots are of no interest for our problem, hence the \ac{DR} should be well computed using $\tilde{Z}$.

  \subsection{Finding the root of \texorpdfstring{$\hat\epsilon$}{the plasma dielectric function.} }

  Now that we can compute $\hat\epsilon$, we can solve the dispersion relation.
  In order to find the root (the zeros) of $\hat\epsilon$, two methods have been tested.

  \paragraph{Exact root finding algorithm\\}
    The first approach has the advantage of finding all of the roots in a given domain.
    It uses Cauchy's argument principle in order to determine the number of roots in a given domain by integrating over the domain contour
    \begin{equation} \label{eq-rootnumber}
      N - P = \frac{1}{2 i \pi} \int_{C} \frac{\hat\epsilon'(\omega)}{\hat\epsilon(\omega)} d\omega
    \end{equation}
    where $N$ and $P$ denote the number of roots and poles in the contour $C$.
    Supposing that there are no poles, we either have
    \begin{enumerate}
      \item $N=0$, hence no roots are presents in the domain,
      \item $N=1$, exactly one root is present,
      \item $N>1$, there are more than one root present.
    \end{enumerate}

    Starting from a large rectangular domain, if $N>1$, we divide the first domain into four sub-domains, and we repeat recursively the algorithm.
    If $N=1$, we can once again use an integral on the contour to find the root \citep{fortune2001}.

    \vspace{1em}
    This algorithm has been implemented in a python package and successfully tested.
    However, it takes a significant amount of time to obtain the solutions, as $\hat\epsilon$ needs to be evaluated several times during the integration.
    Moreover, we have observed that the dispersion relations \cref{eq-drECDI,eq-MIAW} present only one solution with a positive growth rate.
    This solution, corresponding to the instability, is isolated from the others as observed in \cref{fig-numZbis}.
    Hence, a simpler algorithm, as the Gradient descent, can be used.

  \paragraph{Fast root finding algorithm\\}
    A faster root finding algorithm is proposed to solve the dispersion relation by supposing that the wave growing the most is the only root over a domain sufficiently large.
    In other words, it is not close to other roots.
    Hence, we can use a standard minimization method for non-linear equation.
    As the analytic expression of the Hessian or the gradient are unknown, we use the Nelder-Mead method \citep{mckinnon1998}.
    We also tried the Conjugate gradient method by approximating the gradient using finite differences.
    However, even if this method converges in fewer steps, the gradient estimation takes a significant amount of time.
    Powell's method \citep{powell1964} has also been implemented, but the Nelder-Mead method features the best performances.

    The first guess of the iterative Nelder-Mead method is either
    \begin{itemize}
      \item the solution obtained for the previous value of $\vect{k}$,
      \item the solution of the analytic ion acoustic wave dispersion relation (\cref{eq-MIAW}).
    \end{itemize}
    In addition, we can see in \cref{fig-numZbis} that the interesting root is far from the others in the complex plane.
    Hence, a poor initial guess should not affect significantly the converged results, as long as the step size is small enough.
    The results presented hereafter have been obtained using this second faster algorithm.

    \FloatBarrier

\subsection{Use of analytic distribution functions} \label{subsec-DRimpact}
  Before using the electron and ion distribution functions measured in the \ac{PIC} simulations, we compare the dispersion relation for \ac{ECDI} and \ac{IAW} for different analytic distribution functions.

  \paragraph{Ion acoustic wave\\}

  \Cref{fig-IAW_Maxw} shows the comparison with the dispersion relation \cref{eq-drIAWgene} for cold ions and drifting Maxwellian electrons of temperature $\Te=50\,\volt$ and drift velocity $u_e = \sn{2}{6} \,\meter\per\second$ for which the plasma dispersion function $Z_M$ is computed analytically (with the \texttt{plasmapy} package) or numerically.
  The plasma density is $n_e = n_i = \sn{1}{17} \,\per\meter\cubed$.
  The frequency and growth rate obtained using the simplified dispersion relation of \cref{eq-MIAW} is also shown.

  \begin{figure}[hbt]
    \centering
    \includegraphics[width=0.7\textwidth]{IAW_Maxw}
    \caption{IAW frequency $\omega_r$ and growth rate $\gamma$ (scaled by a factor of two) for a Maxwellian distribution function using the Freid and Conte function (labelled Analytic $Z_M$), the numerical estimation of $\tilde{Z}_M$, and the simplified analytic expressions of \cref{eq-MIAW}. }
    \label{fig-IAW_Maxw}
  \end{figure}

  We can see that the three approaches give almost the same solutions.
  The growth rates are all overlapping, hence it is difficult to see the differences.
  For $\omega_r$, the simplified analytic expression returns a slightly different result, but the difference is negligible.
  The numerical evaluation of $\tilde{Z}_M$ gives the same result as the analytic evaluation.

  \Cref{fig-IAW_druv} shows the effect of a Druyvesteyn electron distribution compared to a Maxwellian.
  We recall that a Druyvesteyn distribution follows the expression
  \begin{equation} \label{eq-druyv}
    f_{D}(v) = v_{th}^{-1} C2 \exp \lp -C1 \frac{\norm{v}^4}{v_{th}^4}  \rp ,
  \end{equation}

  where $C1 \simeq \Gamma(3/4)^2 \Gamma(5/4)^{-2}/4 \simeq 0.457 $ and $C2 =\Gamma(3/4)^{1/2} \Gamma(5/4)^{-3/2}2^{-3/2}  \simeq 0.453$ are two normalizing constants, so that the density and the thermal velocity $v_{th}$ are consistent with the Maxwellian distribution.
  The electron density used is $n_e=\sn{1}{17}\,\meter^{-3}$ and the electron temperature is $\Te=50\,\volt$, the ion temperature is $\Ti=0.1\,\volt$, and the drift velocity is $u_e=\sn{1.8}{6}\,\meter\per\second \simeq 300 c_s$ with $c_s=\lde \opi\simeq 6\,\kilo\meter\per\second$.
  We see in \cref{fig-IAW_druv} that the impact of the Druyvesteyn \ac{EVDF} on the \ac{IAW} dispersion relation is small, except that the maximum growth rate is decreased by $15\%$.

  \begin{figure}[!hbt]
    \centering
    \includegraphics[width=\defaultwidth]{IAW_druv}
    \caption{IAW frequency and growth rate for a Maxwellian distribution function using the Freid and Conte function and a Druyvesteyn distribution evaluated with the numerical estimation of $\tilde{Z}$. }
    \label{fig-IAW_druv}
  \end{figure}
  \Cref{fig-valition-solver} shows the evolution of the most growing wave with the electron drift velocity for both the Maxwellian and the Druyvesteyn \ac{EVDF}.
  An illustration of the two distribution functions with a drift equal to the thermal velocity can be seen in \cref{fig-valition-solver}.{\bf b}.
  We see that, as obtained in the analytic dispersion relation \cref{eq-MIAW}, the growth rate is proportional to the drift velocity when $u_e \ll v_{th}$.
  In addition, the wave corresponding to the maximum growth rate depends only weakly of the drift velocity, and we find a good agreement with the analytic values $k_{\theta} \lde =1/\sqrt{2} \simeq 0.707$ and $\omega / \opi = 1/\sqrt{3} \simeq 0.577$.
  Lastly, the shape of the \ac{EVDF} seems to affect only weakly the result.

  \begin{figure}[!hbt]
    \centering
    \includegraphics[width=0.8\textwidth]{comp_Maxw_Druyv_IAW.pdf}
    \caption{({\bf a}) Evolution as a function of the electron drift velocity $u_e$ of the maximum growth rate $\gamma$ and the corresponding wavenumber $k_{\theta}$ and frequency $\omega$ of the \acs{IAW} for both a Maxwellian and a Druyvesteyn \acs{EVDF}, supposing the ions Maxwellian;({\bf b}) the two distribution function for $u_e/c_s = 300$.}
    \label{fig-valition-solver}
  \end{figure}

  \FloatBarrier

  \paragraph{Electron Cyclotron Drift instability\\}

  \Cref{fig-ECDI_druv} shows the frequency and the grow rate for the \ac{ECDI}, defined by \cref{eq-drECDI}, in the same conditions that the \ac{IAW} results, with $k_r \lambda_{De} = 0.05 $.
  The infinite sum over the cyclotron resonances is stopped at $N_{max} = 20$.
  We see in \cref{fig-ECDI_druv} that the cyclotron resonances are present for both distribution functions, and the wave frequency and the growth rate are not much affected by the shape of the \ac{EVDF}.
  For very small radial wavenumber, the numerical resolution crashes, as the argument in $Z(\eta)$ diverges.
  However, in the limit $\eta \rightarrow \infty, Z(\eta) \rightarrow  \frac{1}{\eta}$.
  Hence, we still obtain the cyclotron resonances, as shown in \citet[Fig. 2]{janhunen2018}.

  \begin{figure}[!hbt]
    \centering
    \includegraphics[width=\defaultwidth]{ECDI_druv}
    \caption{\acs{ECDI} frequency and growth rate for a Maxwellian distribution function using the Freid and Conte function and a Druyvesteyn distribution evaluated with the numerical estimation of $\tilde{Z}$, the radial wave number is $k_r \lambda_{De} = 0.05$. The \acs{IAW} \acs{DR} using Maxwellian VDFs is shown }
    \label{fig-ECDI_druv}
  \end{figure}

  We also see in \cref{fig-ECDI_druv} that the \ac{ECDI} \ac{DR} presents the resonances around the \ac{IAW} \ac{DR}.
  This is why in case of resonance broadening, the \ac{ECDI} converged toward a \ac{IAW}-like dispersion relation.

\let\rightmark=\oldrightmark


\section{Model Functions}

The Thrusters module contains methods allowing it to perform several tasks:

\begin{itemize}
	\item \textbf{Set thrusters}: Define and set several thrusters with different parameters, and locations. Parameters include: Minimum On-Time, $I_{sp}$, direction of thrust...
	\item \textbf{Ramp On/Off}: Define ramps that model the imperfect on time and off time for a thruster
	\item \textbf{Compute Forces and Torques}: Gets the forces and torques on the SpaceCraft given the previous definitions
	\item \textbf{Compute mass flow rate }: Computes the time derivative of the mass using $I_{sp}$ and Earth's gravity
\end{itemize}

\section{Model Assumptions and Limitations}

\subsection{Assumptions}

The Thruster module assumes that the thruster is thrusting exactly along it's thrust direction axis. Even if the position is dispersed, the thrust will be constant along that dispersed axis and will not vary.

The mass flow rate is considered to be constant as long as the thrusters are activated. Even in a ramp scenario, we assume that the mass is lost, without contributing to the thrust. Mass flow is therefore the same as long as the valve is open.

\subsection{Limitations}

The ramps in the thrusters modules are made by defining a set of elements to the ramp. They therefore form, by definition, a piecewise-linear ramp. If enough points are added, this will strongly ressemble a polynomial, but the ramps are in essence piecewise constant.

The $I_{sp}$ used for each thruster is considered constant throughout a simulation. This means there is no practical way of doing variable $I_{sp}$ simulations. It can nevertheless be done by stopping the simulation and modifying the values.