%  qd.tex
%
%  This work was supported by the Director, Office of Science, Division
%  of Mathematical, Information, and Computational Sciences of the
%  U.S. Department of Energy under contract number DE-AC03-76SF00098.
%
%  (C) September 2000-2004
\documentclass[11pt]{article}
\usepackage{graphicx}
\usepackage{amsthm}

\pagestyle{plain}

\setlength{\textwidth}{6.5in}
\setlength{\textheight}{8.5in}
\setlength{\topmargin}{-0.2in}
\setlength{\oddsidemargin}{0.0in}
\setlength{\evensidemargin}{0.0in}

% All thm/def/lem/etc... have same numbering
\newtheorem{thm}{Theorem}
\newtheorem{defn}[thm]{Definition}
\newtheorem{lem}[thm]{Lemma}
\newtheorem{prop}[thm]{Proposition}

\theoremstyle{definition}
\newtheorem{alg}[thm]{Algorithm}

\newcommand{\round}{\mathrm{round}}
\newcommand{\fl}{\mathrm{fl}}
\newcommand{\err}{\mathrm{err}}
\newcommand{\ulp}{\mathrm{ulp}}
\newcommand{\hi}{\mathrm{hi}}
\newcommand{\lo}{\mathrm{lo}}
\newcommand{\eps}{\varepsilon}
\newcommand{\epsqd}{\varepsilon_\mathrm{qd}}

\title{Library for Double-Double and Quad-Double Arithmetic\footnotemark[1]}
\author{Yozo Hida\footnotemark[2] \and Xiaoye S. Li\footnotemark[3]
  \and David H. Bailey\footnotemark[3]}
\date{\today}

\begin{document}
\maketitle

% change foot note symbols
\renewcommand{\thefootnote}{\fnsymbol{footnote}}

\footnotetext[1]{This research was supported by the Director,
  Office of Science, Division of Mathematical, Information, and
  Computational Sciences of the U.S. Department of Energy under
  contract number DE-AC03-76SF00098.}
\footnotetext[2]{Computer Science Division, University of California,
  Berkeley, CA 94720 ({\tt yozo@cs.berkeley.edu}).}
\footnotetext[3]{NERSC, Lawrence Berkeley National Laboratory, 1 Cycloton Rd,
  Berkeley, CA 94720 ({\tt xiaoye@nersc.gov}, {\tt dhbailey@lbl.gov}).}

% change footnote symbols back to numbers
\renewcommand{\thefootnote}{\arabic{footnote}}

\vspace{1cm}
\begin{abstract}
  A double-double number is an unevaluated sum of two IEEE double
  precision numbers, capable of representing at least 106 bits of
  significand.   Similarly, a quad-double number is an unevaluated sum of
  four IEEE double precision numbers, capable of representing at least
  212 bits of significand.  Algorithms for various arithmetic operations
  (including the four basic operations and various algebraic and
  transcendental operations) are presented. A C++ implementation of
  these algorithms is also described, along with its C and Fortran
  interfaces.  Performance of the library is also discussed.
\end{abstract}

\newpage
\tableofcontents
\newpage

\section{Introduction} \label{sec:intro}
Multiprecision computation has a variety of application areas, such as
pure mathematics, study of mathematical constants, cryptography,
and computational geometry. Because of this, many arbitrary precision
algorithms and libraries have been developed using only the fixed
precision arithmetic. They can be divided into two groups based on
the way precision numbers are represented. Some libraries store numbers in a
{\em multiple-digit} format, with a sequence of digits coupled with a
single exponent, such as the symbolic computation package
Mathematica, Bailey's MPFUN~\cite{bai-mp}, Brent's MP~\cite{brent} and
GNU MP~\cite{gnu-mp}.  An alternative approach is to store numbers
in a {\em multiple-component} format, where a number is expressed
as unevaluated sums of ordinary floating-point words, each with its own
significand and exponent.  Examples of this format
include~\cite{dek71,pri92,she97}.  The multiple-digit approach can
represent a much larger range of numbers, whereas the multiple-component
approach has the advantage in speed.

We note that many applications would get full benefit from using merely
a small multiple of (such as twice or quadruple) the working precision,
without the need for arbitrary precision.
The algorithms for this kind of ``fixed'' precision can be made
significantly faster than those for arbitrary precision.
Bailey~\cite{bai-dd} and Briggs~\cite{kbriggs97} have developed
algorithms and software for ``double-double'' precision, twice the
double precision. They used the multiple-component format, where a
double-double number is represented as an unevaluated
sum of a leading double and a trailing double.

In this paper we present the algorithms used in the {\tt qd} library,
which implements both double-double and quad-double arithmetic.
A quad-double number is an unevaluated sum of four IEEE doubles.
The quad-double number $(a_0, a_1, a_2, a_3)$ represents the exact
sum $a = a_0 + a_1 + a_2 + a_3$, where $a_0$ is the most sigficant component.
We have designed and implemented algorithms for basic arithmetic
operations, as well as some algebraic and transcendental functions.
We have performed extensive correctness tests and compared the results
with arbitrary precision package MPFUN.
Our quad-precision library is available at
{\tt http://www.nersc.gov/\~{ }dhbailey/mpdist/mpdist.html}.
Our quad-double library has been successfully integrated into a parallel
vortex roll-up simulation code; this is briefly described in
\cite{hida00}.

The rest of the paper is organized as follows.
Section~\ref{sec:prelim} describes some basic properties of IEEE
floating point arithmetic and building blocks for our quad-double
algorithms. In Section~\ref{sec:basic} we present the quad-double
algorithms for basic operations, including renormization, addition,
multiplication and division.
Section~\ref{sec:algebraic} and~\ref{sec:transcendental}
present the algorithms for some algebraic operations and transcendental
functions. Section~\ref{sec:misc} describes some auxiliary functions.
Section~\ref{sec:implement} briefly describes our C++ library
implementing the above algorithms.
Section~\ref{sec:performance} presents the timing results of the
kernel operations on different architectures.
Section~\ref{sec:future} discusses future work.

\section{Preliminaries} \label{sec:prelim}
In this section, we present some basic properties and algorithms of IEEE
floating point arithmetic used in quad-double arithmetic.
These results are based on Dekker \cite{dek71}, Knuth \cite{knu81},
Priest \cite{pri92}, Shewchuk \cite{she97}, and others.  In fact,
many of the algorithms and diagrams are directly taken from, or based on,
Shewchuk's paper.

All basic arithmetics are assumed to be performed in IEEE double format,
with round-to-even rounding on ties.  For any binary operator
$\cdot \in \{+, -, \times, /\}$, we use $\fl(a \cdot b) = a \odot b$ to denote
the floating point result of $a \cdot b$, and define $\err(a \cdot b)$
as $a \cdot b = \fl(a \cdot b) + \err(a \cdot b)$.
Throughout this paper, $\eps = 2^{-53}$ is the machine epsilon for
IEEE double precision numbers, and $\epsqd = 2^{-211}$ is
the precision one expects for quad-double numbers.

\begin{lem} {\rm \cite[p. 310]{she97}}
  Let $a$ and $b$ be two $p$-bit floating point numbers such that
  $|a| \ge |b|$.  Then $|\err(a+b)| \le |b| \le |a|$.
\end{lem}

\begin{lem} {\rm \cite[p. 311]{she97}}
  Let $a$ and $b$ be two $p$-bit floating point numbers.  Then
  $\err(a+b) = (a + b) - \fl(a+b)$ is representable as a $p$-bit
  floating point number.
\end{lem}

\begin{alg} \cite[p. 312]{she97}
  The following algorithm computes $s = \fl(a+b)$ and $e = \err(a+b)$,
  assuming $|a| \ge |b|$.

  \vspace{0.1in}
  \hfill
  \begin{minipage}[t]{4in}
    {\sc Quick-Two-Sum}($a, b$) \\
    \begin{tabular}{rl}
      1. & $s \leftarrow a \oplus b$ \\
      2. & $e \leftarrow b \ominus (s \ominus a)$ \\
      3. & {\bf return} $(s, e)$
    \end{tabular}
  \end{minipage}
\end{alg}

\begin{alg} \cite[p. 314]{she97}
  The following algorithm computes $s = \fl(a+b)$ and $e = \err(a+b)$.
  This algorithm uses three more floating point operations instead of
  a branch.

  \vspace{0.1in}
  \hfill
  \begin{minipage}[t]{4in}
    {\sc Two-Sum}($a, b$) \\
    \begin{tabular}{rl}
      1. & $s \leftarrow a \oplus b$ \\
      2. & $v \leftarrow s \ominus a$ \\
      3. & $e \leftarrow (a \ominus (s \ominus v)) \oplus (b \ominus v)$ \\
      4. & {\bf return} $(s, e)$
    \end{tabular}
  \end{minipage}
\end{alg}

\begin{alg} \cite[p. 325]{she97}
  The following algorithm splits a 53-bit IEEE double precision
  floating point number into $a_{\hi}$ and $a_{\lo}$, each with 26 bits of
  significand, such that $a = a_\hi + a_\lo$.  $a_\hi$ will contain
  the first $26$ bits, while $a_\lo$ will contain the lower $26$ bits.

  \vspace{0.1in} \hfill
  \begin{minipage}[t]{4in}
    {\sc Split}($a$) \\
    \begin{tabular}{rl}
      1. & $t \leftarrow (2^{27}+1) \otimes a$ \\
      2. & $a_\hi \leftarrow t \ominus (t \ominus a)$ \\
      3. & $a_\lo \leftarrow a \ominus a_\hi$ \\
      4. & {\bf return} $(a_\hi, a_\lo)$
    \end{tabular}
  \end{minipage}
\end{alg}

\begin{alg} \cite[p. 326]{she97}
  The following algorithm computes $p = \fl(a \times b)$ and
  $e = \err(a \times b)$.

  \vspace{0.1in} \hfill
  \begin{minipage}[t]{5in}
    {\sc Two-Prod}($a, b$) \\
    \begin{tabular}{rl}
      1. & $p \leftarrow a \otimes b$ \\
      2. & $(a_\hi, a_\lo) \leftarrow$ {\sc Split}($a$) \\
      3. & $(b_\hi, b_\lo) \leftarrow$ {\sc Split}($b$) \\
      4. & $e \leftarrow ((a_\hi \otimes b_\hi \ominus p) \oplus
             a_\hi \otimes b_\lo \oplus a_\lo \otimes b_\hi) \oplus
             a_\lo \otimes b_\lo$  \\
      5. & {\bf return} $(p, e)$
    \end{tabular}
  \end{minipage}
\end{alg}

Some machines have a fused multiply-add instruction (FMA) that
can evaluate expression such as $a \times b \pm c$ with a single
rounding error.  We can take advantage of this instruction to compute
exact product of two floating point numbers much faster.  These
machines include IBM Power series (including the PowerPC), on which
this simplification is tested.

\begin{alg}
  The following algorithm computes $p = \fl(a \times b)$ and
  $e = \err(a \times b)$ on a machine with a FMA instruction.
  Note that some compilers emit FMA instructions for
  $a \times b + c$ but not for $a \times b - c$; in this case, some
  sign adjustments must be made.

  \vspace{0.1in} \hfill
  \begin{minipage}[t]{4in}
    {\sc Two-Prod-FMA}($a, b$) \\
    \begin{tabular}{rl}
      1. & $p \leftarrow a \otimes b$ \\
      2. & $e \leftarrow \fl(a \times b - p)$ \\
      3. & {\bf return} ($p, e$)
    \end{tabular}
  \end{minipage}
\end{alg}

The algorithms presented are the basic building blocks of quad-double
arithmetic, and are represented in Figures \ref{quick_two_sum_fig},
\ref{two_sum_fig}, and \ref{two_prod_fig}.  Symbols for normal
double precision sum and product are in Figure~\ref{normal_sum_prod_fig}.

\begin{figure}
  \hfill
  \begin{minipage}[t]{2in}
    \begin{center}
      \includegraphics{quick-two-sum.eps}
      \caption{\label{quick_two_sum_fig}{\sc Quick-Two-Sum}}
    \end{center}
  \end{minipage}
  \begin{minipage}[t]{2in}
    \begin{center}
      \includegraphics{two-sum.eps}
      \caption{\label{two_sum_fig}{\sc Two-Sum}}
    \end{center}
  \end{minipage}
  \begin{minipage}[t]{2in}
    \begin{center}
      \includegraphics{two-prod.eps}
      \caption{\label{two_prod_fig}{\sc Two-Prod}}
    \end{center}
  \end{minipage}
\end{figure}

\begin{figure}
  \begin{center}
    \includegraphics{normal_sum_prod.eps}
    \caption{\label{normal_sum_prod_fig}Normal IEEE double precision sum and product}
  \end{center}
\end{figure}

\section{Basic Operations} \label{sec:basic}
\subsection{Renormalization}
A quad-double number is an unevaluated sum of four IEEE double numbers.
The quad-double number $(a_0, a_1, a_2, a_3)$ represents the exact
sum $a = a_0 + a_1 + a_2 + a_3$.  Note that for any given representable
number $x$, there can be many representations as an unevaluated sum of
four doubles.  Hence we require that the quadruple $(a_0, a_1, a_2, a_3)$
to satisfy
\begin{displaymath}
  |a_{i+1}| \le \frac{1}{2}\ulp(a_i)
\end{displaymath}
for $i = 0, 1, 2$, with equality occurring only if $a_i = 0$ or
the last bit of $a_i$ is $0$ (that is, round-to-even is used in case
of ties).  Note that the first double $a_0$ is a double-precision
approximation to the quad-double number $a$, accurate to almost
half an ulp.

\begin{lem}
  For any quad-double number $a = (a_0, a_1, a_2, a_3)$, the normalized
  representation is unique.
\end{lem}

Most of the algorithms described here produce an expansion that
is not of canonical form -- often having overlapping bits.
Therefore, a five-term expansion is produced, and then renormalized
to four components.

\begin{alg}
  \label{renorm_alg}
  This renormalization procedure is a variant of Priest's renormalization
  method \cite[p. 116]{pri92}.  The input is a five-term expansion with
  limited overlapping bits, with $a_0$ being the most significant component.

  \vspace{0.1in} \hfill
  \begin{minipage}[t]{5in}
    {\sc Renormalize}($a_0, a_1, a_2, a_3, a_4$) \\
    \begin{tabular}{rl}
      1.  & $(s, t_4) \leftarrow$ {\sc Quick-Two-Sum}($a_3, a_4$) \\
      2.  & $(s, t_3) \leftarrow$ {\sc Quick-Two-Sum}($a_2, s$)   \\
      3.  & $(s, t_2) \leftarrow$ {\sc Quick-Two-Sum}($a_1, s$)   \\
      4.  & $(t_0, t_1) \leftarrow$ {\sc Quick-Two-Sum}($a_0, s$) \\
      \\
      5.  & $s \leftarrow t_0$ \\
      6.  & $k \leftarrow 0$   \\
      7.  & {\bf for\footnotemark[1]} $i \leftarrow 1, 2, 3, 4$ \\
      8.  & \quad $(s, e) \leftarrow$ {\sc Quick-Two-Sum}($s, t_i$) \\
      9.  & \quad {\bf if} $e \ne 0$             \\
      10. & \quad \quad $b_k \leftarrow s$       \\
      11. & \quad \quad $s \leftarrow e$         \\
      12. & \quad \quad $k \leftarrow k + 1$     \\
      13. & \quad {\bf end if}  \\
      14. & {\bf end for} \\
      15. & {\bf return} $(b_0, b_1, b_2, b_3)$
    \end{tabular}
  \end{minipage}
\end{alg}

\footnotetext[1]{In the implementation, this loop is unrolled to several
  {\tt if} statements.}

Necessary conditions for this renormalization algorithm to work correctly
are, unfortunately, not known.  Priest proves that if the input expansion
does not overlap by more than 51 bits, then the algorithm works correctly.
However, this condition is by no means necessary; that the renormalization
algorithm (Algorithm \ref{renorm_alg})
works on all the expansions produced by the algorithms below
remains to be shown.

\subsection{Addition}
\subsubsection{Quad-Double + Double}
The addition of a double precision number to a quad-double number
is similar to Shewchuk's {\sc Grow-Expansion} \cite[p. 316]{she97}, but the double
precision number $b$ is added to a quad-double number $a$ from
most significant component first (rather than from least significant).
This produces a five-term expansion which is the exact result,
which is then renormalized.  See Figure~\ref{qd_add_qd_d_fig}.

\begin{figure}
  \begin{center}
    \includegraphics{qd_add_qd_d.eps}
    \caption{\label{qd_add_qd_d_fig}Quad-Double + Double}
  \end{center}
\end{figure}

Since the exact result is computed, then normalized to four components,
this addition is accurate to at least the first 212 bits of the result.

\subsubsection{Quad-Double + Quad-Double}
We have implemented two algorithms for addition.  The first one
is faster, but only satisfies the weaker (Cray-style) error bound
$a \oplus b = (1 + \delta_1)a + (1 + \delta_2)b$ where the magnitude
of $\delta_1$ and $\delta_2$ is bounded by $\epsqd = 2^{-211}$.

\begin{figure}
  \begin{center}
    \includegraphics{qd_add.eps}
    \caption{\label{qd_add_fig}Quad-Double + Quad-Double}
  \end{center}
\end{figure}

Figure \ref{qd_add_fig} best describes the first addition algorithm of two
quad-double numbers.  In the diagram, there are three large boxes
with three inputs to them.  These are various {\sc Three-Sum} boxes,
and their internals are shown in Figure \ref{three_sum_fig}.

\begin{figure}
  \begin{center}
    \includegraphics{three-sum.eps} \includegraphics{three-sum-2.eps}
    \includegraphics{three-sum-3.eps}
    \caption{\label{three_sum_fig}{\sc Three-Sum}s}
  \end{center}
\end{figure}

Now for a few more lemmas.
\begin{lem}
  \label{two_sum_bound}
  Let $a$ and $b$ be two double precision floating point numbers.
  Let $M = \max(|a|, |b|)$.  Then $|\fl(a+b)| \le 2M$, and consequently,
  $|\err(a+b)| \le \frac{1}{2}\ulp(2M) \le 2 \eps M$.
\end{lem}

\begin{lem}
  \label{three_sum_bound}
  Let $x, y,$ and $z$ be inputs to {\sc Three-Sum}.
  Let $u, v, w, r_0, r_1,$ and $r_2$ be as indicated in Figure
  \ref{three_sum_fig}.  Let $M = \max (|x|, |y|, |z|)$.  Then
  $|r_0| \le 4M$, $|r_1| \le 8 \eps M$, and $|r_2| \le 8 \eps^2 M$.
\end{lem}
\begin{proof} This follows from applying Lemma \ref{two_sum_bound}
to each of the three {\sc Two-Sum} boxes.
First {\sc Two-Sum} gives $|u| \le 2M$ and
$|v| \le 2\eps M$.  Next {\sc Two-Sum} (adding $u$ and $z$) gives
$|r_0| \le 4M$ and $|w| \le 4\eps M$.  Finally, the last {\sc Two-Sum}
gives the desired result.
\end{proof}

Note that the two other {\sc Three-Sum}s shown are simplification
of the first {\sc Three-Sum}, where it only computes one or two components,
instead of three; thus the same bounds apply.

The above bound is not at all tight; $|r_0|$ is bounded closer
to $3M$ (or even $|x| + |y| + |z|$), and this makes the bounds for $r_1$
and $r_2$ correspondingly smaller.  However, this suffices for the
following lemma.

\begin{lem}\label{sum_lemma}
  The five-term expansion before the renormalization step in the
  quad-double addition algorithm shown in Figure \ref{qd_add_fig} errs
  from the true result by less than $\epsqd M$, where $M = \max(|a|, |b|)$.
\end{lem}
\begin{proof}
This can be shown by
judiciously applying Lemmas \ref{two_sum_bound} and \ref{three_sum_bound}
to all the {\sc Two-Sum}s and {\sc Three-Sum}s in Figure \ref{qd_add_fig}.
See Appendix \ref{proof_appendix} for detailed proof.
\end{proof}

Assuming that the renormalization
step works (this remains to be proven), we can then obtain the error bound
\begin{displaymath}
  \fl(a+b) = (1 + \delta_1) a + (1 + \delta_2) b \qquad \textrm{with} \quad
  |\delta_1|, |\delta_2| \le \epsqd.
\end{displaymath}

Note that the above algorithm for addition is particularly suited to
modern processors with instruction level parallelism, since the first
four {\sc Two-Sum}s can be evaluated in parallel.  Lack of branches
before the renormalization step also helps to keep the pipelines full.

Note that the above algorithm does not satisfy the IEEE-style error
bound
\begin{displaymath}
  \fl(a+b) = (1+\delta)(a+b) \qquad \textrm{with} \quad
  |\delta| \le 2\epsqd \textrm{ or so.}
\end{displaymath}
To see this, let $a = (u, v, w, x)$ and $b = (-u, -v, y, z)$,
where none of $w, x, y, z$ overlaps and $|w| > |x| > |y| > |z|$.
Then the above algorithm produces $c = (w, x, y, 0)$ instead
of $c = (w, x, y, z)$ required by the stricter bound.

The second algorithm, due to J. Shewchuk and S. Boldo, computes the first
four components of the {\em result} correctly.  Thus it satisfies
more strict error bound
\begin{displaymath}
  \fl(a+b) = (1+\delta)(a+b) \qquad \textrm{with} \quad
  |\delta| \le 2\epsqd \textrm{ or so.}
\end{displaymath}
However, it has a corresponding speed penalty; it runs significantly slower
(factor of $2$--$3.5$ slower).

The algorithm is similar to Shewchuk's {\sc Fast-Expansion-Sum}
\cite[p. 320]{she97},
where it merge-sorts the two expansions.  To prevent components with
only a few significant bits to be produced, a double-length accumulator
is used so that a component is output only if the inputs gets small
enough to not affect it.

\begin{alg}
  \label{double_accum_alg}
  Assuming that $u, v$ is a two-term expansion, the following algorithm
  computes the sum $(u, v) + x$, and outputs the significant component
  $s$ if the remaining components contain more than one double worth
  of significand. $u$ and $v$ are modified to represent the other
  two components in the sum.

  \vspace{0.1in} \hfill
  \begin{minipage}[t]{5in}
    {\sc Double-Accumulate}($u, v, x$) \\
    \begin{tabular}{rl}
      1.  & $(s, v) \leftarrow$ {\sc Two-Sum}($v, x$)  \\
      2.  & $(s, u) \leftarrow$ {\sc Two-Sum}($u, s$)  \\
      3.  & {\bf if} $u = 0$ \\
      4.  & \quad $u \leftarrow s$ \\
      5.  & \quad $s \leftarrow 0$ \\
      6.  & {\bf end if} \\
      7.  & {\bf if} $v = 0$ \\
      8.  & \quad $v \leftarrow u$ \\
      9.  & \quad $u \leftarrow s$ \\
      10. & \quad $s \leftarrow 0$ \\
      11. & {\bf end if}   \\
      12. & {\bf return} ($s, u, v$) \\
    \end{tabular}
  \end{minipage}
\end{alg}

The accurate addition scheme is given by the following algorithm.
\begin{alg}
  \label{accurate_add_alg}
  This algorithm computes the sum of two quad-double numbers
  $a = (a_0, a_1, a_2, a_3)$ and $b = (b_0, b_1, b_2, b_3)$.
  Basically it merge-sorts the eight doubles, and performs
  {\sc Double-Accumulate} until four components are obtained.

  \vspace{0.1in} \hfill
  \begin{minipage}[t]{5in}
    {\sc QD-Add-Accurate}($a, b$) \\
    \begin{tabular}{rl}
      1.  & $(x_0, x_1, \ldots, x_7) \leftarrow$
          {\sc Merge-Sort}$(a_0, a_1, a_2, a_3, b_0, b_1, b_2, b_3)$ \\
      2.  & $u \leftarrow 0$ \\
      3.  & $v \leftarrow 0$ \\
      4.  & $k \leftarrow 0$ \\
      5.  & $i \leftarrow 0$ \\
      6.  & {\bf while} $k < 4$ {\bf and} $i < 8$ {\bf do} \\
      7.  & \quad $(s,u,v)\leftarrow$ {\sc Double-Accumulate}$(u, v, x_i)$ \\
      8.  & \quad {\bf if} $s \ne 0$ \\
      9.  & \quad \quad $c_k \leftarrow s$ \\
     10.  & \quad \quad $k \leftarrow k + 1$ \\
     11.  & \quad {\bf end if} \\
     12.  & \quad $i \leftarrow i + 1$ \\
     13.  & {\bf end while} \\
     14.  & {\bf if} $k < 2$ {\bf then} $c_{k+1} \leftarrow v$ \\
     15.  & {\bf if} $k < 3$ {\bf then} $c_k \leftarrow u$ \\
     16.  & {\bf return} {\sc Renormalize}$(c_0, c_1, c_2, c_3)$
    \end{tabular}
  \end{minipage}
\end{alg}

\subsection{Subtraction}
Subtraction $a - b$ is implemented as the addition $a + (-b)$,
so it has the same algorithm and properties as that of addition.
To negate a quad-double number, we can just simply negate each component.
On a modern C++ compiler with inlining, the overhead is
noticeable but not prohibitive (say $5\%$ or so).

\subsection{Multiplication}
Multiplication is basically done in a straightforward way, multiplying
term by term and accumulating.  Note that unlike addition, there
are no possibilities of massive cancellation in multiplication, so
the following algorithms satisfy the IEEE style error bound
$a \otimes b = (1 + \delta)(a \times b)$ where $\delta$ is bounded
by $\epsqd$.

\subsubsection{Quad-Double $\times$ Double}
Let $a = (a_0, a_1, a_2, a_3)$ be a quad-double number, and let $b$ be
a double precision number.  Then the product is the sum of four terms,
$a_0 b + a_1 b + a_2 b + a_3 b$.  Note that $|a_3| \le \eps^3 |a_0|$,
so $|a_3 b| \le \eps^3 |a_0 b|$, and thus only the first 53 bits of
the product $a_3 b$ need to be computed.  The first three terms are
computed exactly using {\sc Two-Prod} (or {\sc Two-Prod-FMA}).
All the terms are then accumulated in a similar fashion as addition.
See Figure \ref{qd_mul_qd_d_fig}.

\begin{figure}
  \begin{center}
    \includegraphics{qd_mul_qd_d.eps}
    \caption{\label{qd_mul_qd_d_fig}Quad-Double $\times$ Double}
  \end{center}
\end{figure}

\subsubsection{Quad-Double $\times$ Quad-Double}
Multiplication of two quad-double numbers becomes a bit complicated,
but nevertheless follows the same idea.  Let $a = (a_0, a_1, a_2, a_3)$
and $b = (b_0, b_1, b_2, b_3)$ be two quad-double numbers.  Assume
(without loss of generality) that $a$ and $b$ are order 1.
After multiplication, we need to accumulate $13$ terms of order $O(\eps^4)$
or higher.
\begin{displaymath}
  \begin{array}{rcl@{\qquad}l}
    a \times b &\approx& a_0 b_0 & O(1) \textrm{ term} \\
    & & +\; a_0 b_1 + a_1 b_0 & O(\eps) \textrm{ terms}\\
    & & +\;a_0 b_2 + a_1 b_1 + a_2 b_0 & O(\eps^2) \textrm{ terms}\\
    & & +\;a_0 b_3 + a_1 b_2 + a_2 b_1 + a_3 b_0 & O(\eps^3) \textrm{ terms}\\
    & & +\;a_1 b_3 + a_2 b_2 + a_3 b_1 & O(\eps^4) \textrm{ terms}
  \end{array}
\end{displaymath}
Note that smaller order terms (such as $a_2 b_3$, which is $O(\eps^5)$)
are not even computed, since they are not needed to get the first
212 bits.  The $O(\eps^4)$ terms are computed using normal double
precision arithmetic, as only their first few bits are needed.

For $i+j \le 3$, let $(p_{ij}, q_{ij}) = ${\sc Two-Prod}($a_i$, $b_j$).
Then $p_{ij} = O(\eps^{i+j})$ and $q_{ij} = O(\eps^{i+j+1})$.
Now there are one term ($p_{00}$) of order $O(1)$, three
($p_{01}$, $p_{10}$, $q_{00}$) of order $O(\eps)$, five
($p_{02}$, $p_{11}$, $p_{20}$, $q_{01}$, $q_{10}$)
of order $O(\eps^2)$, seven of order $O(\eps^3)$,
and seven of order $O(\eps^4)$.
Now we can start accumulating all the terms by their order,
starting with $O(\eps)$ terms (see Figure \ref{qd_mul_accum_fig}).

\begin{figure}
  \begin{center}
    \includegraphics{qd_mul_accum.eps}
    \caption{\label{qd_mul_accum_fig}Quad-Double $\times$ Quad-Double accumulation phase}
  \end{center}
\end{figure}

In the diagram, there are four different summation boxes.
The first (topmost) one is {\sc Three-Sum}, same as the one in
addition.  The next three are, respectively, {\sc Six-Three-Sum}
(sums six doubles and outputs the first three components),
{\sc Nine-Two-Sum} (sums nine doubles and outputs the first two components),
and {\sc Nine-One-Sum} (just adds nine doubles using normal arithmetic).

{\sc Six-Three-Sum} computes the sum of six doubles to three double
worth of accuracy (i.e., to relative error of $O(\eps^3)$).  This is
done by dividing the inputs into two groups of three, and
performing {\sc Three-Sum} on each group.  Then the two sums
are added together, in a manner similar to quad-double addition.
See Figure \ref{six_three_sum_fig}.

{\sc Nine-Two-Sum} computes the sum of nine doubles to double-double
accuracy.  This is done by pairing the inputs to create four double-double
numbers and a single double precision number, and performing
addition of two double-double numbers recursively until one arrives
at a double-double output.  The double-double addition (the large square
box in the diagram) is the same as David Bailey's algorithm \cite{bai-dd}.
See Figure \ref{nine_two_sum_fig}.

\begin{figure}
  \begin{center}
    \includegraphics{six-three-sum.eps}
    \caption{\label{six_three_sum_fig}{\sc Six-Three-Sum}}
  \end{center}
\end{figure}

\begin{figure}
  \begin{center}
    \includegraphics{nine-two-sum.eps}
    \caption{\label{nine_two_sum_fig}{\sc Nine-Two-Sum}}
  \end{center}
\end{figure}

If one wishes to trade few bits of accuracy for speed, we don't
even need to compute the $O(\eps^4)$ terms; they can affect the
first 212 bits only by carries during accumulation.
In this case, we can compute the
$O(\eps^3)$ terms using normal double precision arithmetic,
thereby speeding up multiplication considerably.

Squaring a quad-double number can be done significantly
faster since the number of terms that needs to be accumulated
can be reduced due to symmetry.

\subsection{Division}
Division is done by the familiar long division algorithm.
Let $a = (a_0, a_1, a_2, a_3)$ and $b = (b_0, b_1, b_2, b_3)$ be
quad-double numbers.  We can first compute
an approximate quotient $q_0 = a_0 / b_0$.  We then compute
the remainder $r = a - q_0 \times b$, and compute the
correction term $q_1 = r_0 / b_0$.  We can continue this process
to obtain five terms, $q_0,\; q_1,\; q_2,\; q_3$, and $q_4$.
(only four are needed if few bits of accuracy is not important).

Note that at each step, full quad-double multiplication and
subtraction must be done since most of the bits will be canceled
when computing $q_3$ and $q_4$.  The five-term (or four-term)
expansion is then renormalized to obtain the quad-double quotient.

\section{Algebraic Operations} \label{sec:algebraic}
\subsection{$N$-th Power}
$N$-th Power computes $a^n$, given a quad-double number $a$ and an
integer $n$.  This is simply done by repeated squaring, borrowed
from David Bailey \cite{bai-dd}.

\subsection{Square Root}
Square root computes $\sqrt{a}$ given a quad-double number $a$.
This is done with Newton iteration on the function
\begin{displaymath}
  f(x) = \frac{1}{x^2} - a
\end{displaymath}
which has the roots $\pm a^{-1/2}$. This gives rise to the iteration
\begin{displaymath}
  x_{i+1} = x_i + \frac{x_i (1 - ax_i^2)}{2}.
\end{displaymath}
Note that the iteration does not require division of quad-double
numbers.  (Multiplication by $1/2$ can be done component-wise.)
Since Newton's iteration is locally quadratically convergent,
only about two iterations are required if one starts out with
double precision approximation $x_0 = \sqrt{a_0}$.  (In the
implementation it is done three times.)  After $x = a^{-1/2}$ is
computed, we perform a multiplication to obtain $\sqrt{a} = ax$.

\subsection{$N$-th Root}
$N$-th Root computes $\sqrt[n]{a}$ given a quad-double number $a$
and an integer $n$.  This is done again by Newton's iteration on
the function
\begin{displaymath}
  f(x) = \frac{1}{x^n} - a
\end{displaymath}
which has the roots $a^{-1/n}$. This gives rise to the iteration
\begin{displaymath}
  x_{i+1} = x_i + \frac{x_i (1 - ax_i^n)}{n}.
\end{displaymath}
Three iterations are performed, although twice is almost sufficient.
After $x = a^{-1/n}$ is computed, we can invert to obtain $a^{1/n} = 1/x$.

\section{Transcendental Operations} \label{sec:transcendental}
\subsection{Exponential}
The classic Taylor-Maclaurin series is used to evaluate $e^x$.  Before
using the Taylor series, the argument is reduced by noting that
\begin{displaymath}
  e^{kr + m \log 2} = 2^m (e^r)^k,
\end{displaymath}
where the integer $m$ is chosen so that $m \log 2$ is closest to $x$.
This way, we can make $|kr| \le \frac{1}{2} \log 2 \approx 0.34657$.
Using $k = 256$, we have $|r| \le \frac{1}{512} \log 2 \approx 0.001354$.
Now $e^r$ can be evaluated using familiar Taylor series.  The argument
reduction substantially speeds up the convergence of the series, as
at most 18 terms are need to be added in the Taylor series.

\subsection{Logarithm}
Since the Taylor series for logarithm converges much more slowly than
the series for exponential, instead we use Newton's iteration to
find the zero of the function $f(x) = e^x - a$.  This leads to
the iteration
\begin{displaymath}
  x_{i+1} = x_i + ae^{-x_i} - 1,
\end{displaymath}
which is repeated three times.

\subsection{Trigonometrics}
Sine and cosine are computed using Taylor series after argument reduction.
To compute $\sin x$ and $\cos x$, the argument $x$ is first reduced modulo
$2 \pi$, so that $|x| \le \pi$.  Now noting that $\sin (y + k \pi /2)$
and $\cos (y + k \pi / 2)$ are of the form $\pm \sin y$ or $\pm \cos y$
for all integers $k$, we can reduce the argument modulo $\pi/2$ so that
we only need to compute $\sin y$ and $\cos y$ with $|y| \le \pi / 4$.

Finally, write $y = z + m (\pi / 1024)$ where the integer $m$ is chosen
so that $|z| \le \pi / 2048 \approx 0.001534$.  Since $|y| \le \pi / 4$,
we can assume that $|m| \le 256$.
By using a precomputed table
of $\sin (m \pi / 1024)$ and $\cos (m \pi / 1024)$, we note that
\begin{displaymath}
  \sin (z + m \pi / 1024) = \sin z \cos (m \pi / 1024) +
  \cos z \sin (m \pi / 1024)
\end{displaymath}
and similarly for $\cos (z + m \pi / 1024)$.  Using this argument
reduction significantly increases the convergence rate of sine,
as at most 10 terms need be added.

Note that if both cosine and sine are needed, then one can compute
the cosine using the formula
\begin{displaymath}
  \cos x = \sqrt{1 - \sin^2 x}.
\end{displaymath}

The values of $\sin (m \pi / 1024)$ and $\cos (m \pi / 1024)$ are
precomputed by using arbitrary precision package such as MPFUN \cite{bai-mp}
using the formula
\begin{displaymath}
    \sin \left( \frac{\theta}{2} \right) =
    \frac{1}{2} \sqrt{2 - 2 \cos \theta}
\end{displaymath}
\begin{displaymath}
    \cos \left( \frac{\theta}{2} \right) =
    \frac{1}{2} \sqrt{2 + 2 \cos \theta}
\end{displaymath}
Starting with $\cos \pi = -1$, we can recursively use the above formula
to obtain $\sin (m \pi / 1024)$ and $\cos (m \pi / 1024)$.

\subsection{Inverse Trigonometrics}
Inverse trigonometric function $\arctan$ is computed using Newton
iteration on the function $f(x) = \sin x - a$.

\subsection{Hyperbolic Functions}
Hyperbolic sine and cosine are computed using
\begin{displaymath}
  \sinh x = \frac{e^x - e^{-x}}{2} \qquad \cosh x = \frac{e^x + e^{-x}}{2}
\end{displaymath}
However, when $x$ is small (say $|x| \le 0.01$), the above formula for
$\sinh$ becomes unstable, and the Taylor series is used instead.

\section{Miscellaneous Routines} \label{sec:misc}
\subsection{Input / Output}
  Binary to decimal conversion of quad-double number $x$ is done by
determining the integer $k$ such that $1 \le |x 10^{-k}| < 10$,
and repeatedly extracting digits and multiplying by 10.  To minimize
error accumulation, a table of accurately precomputed powers of 10
is used.  This table is also used in decimal to binary conversion.

\subsection{Comparisons}
Since quad-double numbers are fully renormalized after each
operation, comparing two quad-double number for equality can
be done component-wise.  Comparing the size can be done from
most significant component first, similar to dictionary ordering
of English words.  Comparison to zero can be done just by checking
the most significant word.

\subsection{Random Number Generator}
The quad-double random number generator produces a quad-double
number in the range $[0, 1)$, uniformly distributed.  This is
done by choosing the first 212 bits randomly.  A 31-bit system-supplied
random number generator is used to generate 31 bits at a time,
this is repeated $\lceil 212 / 31 \rceil = 7$ times to get
all 212 bits.

\section{C++ Implementation} \label{sec:implement}
  The quad-double library is implemented in ANSI C++, taking full
advantage of operator / function overloading and user-defined data
structures.  The library should compile fine with ANSI Standard compliant
C++ compilers.  Some of the test codes may not work with compilers
lacking full support for templates.  Please see the files {\tt README}
and {\tt INSTALL} for more details on the implementation and build
instructions.

  Full C++ implementation of double-double library is included as
a part of the quad-double library, including full support for mixing
three types: double, double-double, and quad-double.  In order to use
the library, one must include the header file {\tt qd.h}
and link the code with the library {\tt libqd.a}.
Quad-double variables are declared as {\tt qd\_real}, while double-double
variables are declared as {\tt dd\_real}.

A sample C++ program is given below.

\begin{tt}\begin{verbatim}
  #include <iostream>
  #include <qd/qd.h>

  using std::cout;
  using std::endl;

  int main() {
    int oldcw;
    fpu_fix_start(&oldcw);     // see notes on x86 machines below.

    qd_real a = "3.141592653589793238462643383279502884197169399375105820";
    dd_real b = "2.249775724709369995957";
    dd_real r;

    r = a + b;
    cout << "pi + e = " << r << endl;

    r = sqrt(r + 1.0);

    fpu_fix_end(&oldcw);       // see notes on x86 machines below.
    return 0;
  }
\end{verbatim}\end{tt}

Note that strings must be used to assign to a quad-double (or double-double)
numbers; otherwise the double precision approximation is assigned.
For example, {\tt a = 0.1} does not assign quad-double precision 0.1,
but rather a double precision number 0.1.  Instead, use {\tt a = "0.1"}.

Common constants such as $\pi$, $\pi/2$, $\pi/4$, $e$, $\log 2$ are
 provided as {\tt qd\_real::\_pi}, {\tt qd\_real::\_pi2},
{\tt qd\_real::\_pi4}, {\tt qd\_real::\_e}, and {\tt qd\_real::\_log2}.
These were computed using an arbitrary precision package (MPFUN++
\cite{cha98}), and therefore are accurate to the last bit.

\noindent{\bf Note on Intel x86 Processors}.
The algorithms in this library assume IEEE double precision floating
point arithmetic.  Since Intel x86 processors have extended (80-bit)
floating point registers, the round-to-double flag must be enabled in
the control word of the FPU for this library to function properly
under x86 processors.  The function {\tt fpu\_fix\_start} turns
on the round-to-double bit in the FPU control word, while
{\tt fpu\_fix\_end} will restore the original state.

\section{Performance} \label{sec:performance}
Performance of various operations on quad-double numbers on a variety
of machines are presented in Table \ref{timing_table}.  The tested
machines are
\begin{itemize}
\item Intel Pentium II, 400 MHz, Linux 2.2.16, g++ 2.95.2 compiler,
  with {\tt -O3 -funroll-loops -finline-functions -mcpu=i686 -march=i686}
  optimizations.
\item Sun UltraSparc 333 MHz, SunOS 5.7, Sun CC 5.0 compiler,
  with {\tt -xO5 -native} optimizations.
\item PowerPC 750 (Apple G3), 266 MHz, Linux 2.2.15, g++ 2.95.2 compiler,
  with {\tt -O3 -funroll-\\loops -finline-functions} optimizations.
\item IBM RS/6000 Power3, 200 MHz, AIX 3.4, IBM xlC compiler,
  with {\tt -O3 -qarch=pwr3 -qtune\\=pwr3 -qstrict} optimizations.
\end{itemize}

\noindent {\bf Note}: For some reason, GNU C++ compiler ({\tt g++}) has
a terrible time optimizing the code for multiplication; it runs more than
15 times slower than the code compiled by Sun's CC compiler.

\begin{table}[t]
  \begin{center}
  \label{timing_table}
  \begin{tabular}{|l|c|c|c|c|} \hline
    Operation &
    \begin{tabular}{c}Pentium II \\ 400MHz \\ Linux 2.2.16 \end{tabular} &
    \begin{tabular}{c}UltraSparc \\ 333 MHz \\ SunOS 5.7 \end{tabular} &
    \begin{tabular}{c}PowerPC 750 \\ 266 MHz \\ Linux 2.2.15 \end{tabular} &
    \begin{tabular}{c}Power3 \\  200 MHz \\ AIX 3.4 \end{tabular} \\
    \hline
    \multicolumn{5}{|l|}{{\em Quad-double}} \\
    add          &  0.583 &  0.580 &  0.868 &  0.710 \\
    accurate add &  1.280 &  2.464 &  2.468 &  1.551 \\
    mul          &  1.965 &  1.153 &  1.744 &  1.131 \\
    sloppy mul   &  1.016 &  0.860 &  1.177 &  0.875 \\
    div          &  5.267 &  6.440 &  8.210 &  6.699 \\
    sloppy div   &  4.080 &  4.163 &  6.200 &  4.979 \\
    sqrt         & 23.646 & 15.003 & 21.415 & 16.174 \\ \hline
    \multicolumn{5}{|l|}{{\em MPFUN}}\\
    add		 &  5.729 &  5.362 &  ---   &  4.651 \\
    mul		 &  7.624 &  7.630 &  ---   &  5.837 \\
    div     	 & 10.102 & 10.164 &  ---   &  9.180 \\ \hline
  \end{tabular}
  \caption{Performance of some Quad-Double algorithms on several machines.
    All measurements are in microseconds. We include the performance of
    MPFUN~\cite{bai-mp} as a comparison. Note, we do not have the MPFUN
    measurements on the PowerPC, because we do not have a Fortran-90 compiler.}
  \end{center}
\end{table}

Most of the routines runs noticeably faster if implemented in C,
it seems that C++ operator overloading has some overhead associated
with it -- most notably excessive copying of quad-double numbers.
This occurs because operator overloading does not account for
where the result is going to be placed.  For example,
for the code
\begin{quote}\begin{tt}c = a + b;\end{tt}\end{quote}
the C++ compiler often emits the code equivalent to
\begin{quote}\begin{tt}
\begin{verbatim}
qd_real temp;
temp = operator+(a, b);     // Addition
operator=(c, temp);         // Copy result to c
\end{verbatim}
\end{tt}\end{quote}
In C, this copying does not happen, as one would just write
\begin{quote}\begin{tt}\begin{verbatim}
c_qd_add(a, b, c);          // Put (a+b) into c
\end{verbatim}\end{tt}\end{quote}
where the addition routine knows where to put the result directly.
This problem is somewhat alleviated by inlining, but not completely
eliminated.  There are techniques to avoid these kinds of copying~\cite{c++},
but they have
their own overheads associated with them and is not practical for
quad-double with only 32 bytes of data\footnote{These techniques
are feasible, for larger data structures, such as for much higher
precision arithmetics, where copying of data becomes time consuming.}.

\section{Future Work} \label{sec:future}
Currently, the basic routines do not have a full correctness proof.
The correctness of these routines rely on the fact that renormalization
step works; Priest proves that it does work if the input does not overlap
by 51 bits and no three components overlap at a single bit.  Whether
such overlap can occur in any of these algorithm needs to be proved.

There are improvements due in the remainder operator, which computes
$a - \round(a/b) \times b$, given quad-double numbers $a$ and $b$.
Currently, the library does the na\"\i ve method of just divide, round,
multiply, and subtract.  This leads to loss of accuracy when $a$ is large
compared to $b$.  Since this routine is used in argument reduction for
exponentials, logarithms and trigonometrics, a fix is needed.

A natural extention of this work is to extend the precision beyond
quad-double.  Algorithms for quad-double additions and multiplication
can be extended to higher precisions, however, with more components,
asymptotically faster algorithm due to S. Boldo and J. Shewchuk may
be preferrable (i.e. Algorithm~\ref{accurate_add_alg}).
One limitation these higher precision expansions have
is the limited exponent range -- same as that of double.  Hence
the maximum precision is about 2000 bits (39 components),
and this occurs only if the first component is near overflow and the
last near underflow.

\section{Acknowledgements}
We thank Jonathan Shewchuk,
Sylvie Boldo, and James Demmel for constructive discussions on
various basic algorithms.  In particular, the accurate version of
addition algorithm is due to S. Boldo and J. Shewchuk.  Problems with
remainder was pointed out by J.Demmel.

\appendix
\newpage
\section{Proof of Quad-Double Addition Error Bound (Lemma \ref{sum_lemma})}
\label{proof_appendix}

\noindent
{\bf Lemma \ref{sum_lemma}}.
\emph{The five-term expansion before the renormalization step in the
quad-double addition algorithm shown in Figure \ref{qd_add_fig} errs
from the true result by less than $\epsqd M$, where $M = \max(|a|, |b|)$.}

\begin{proof}
  The proof is done by applying Lemmas \ref{two_sum_bound} and
\ref{three_sum_bound} to each of {\sc Two-Sum}s and {\sc Three-Sum}s.
Let $e_0, e_1, e_2, e_3, t_1, t_2, t_3, x_0, x_1, x_2, x_3, x_4, u, v,
w, z, f_1, f_2$, and $f_3$ be as shown in Figure \ref{qd_add_proof_fig}.

We need to show
that the five-term expansion $(x_0, x_1, x_2, x_3, x_4)$ errs from the
true result by less than $\epsqd M$, where $M = \max(|a_0|, |b_0|)$.
Note that the only place that any error is introduced is in {\sc Three-Sum} 7
and {\sc Three-Sum} 8, where lower order terms $f_1, f_2,$ and $f_3$ are discarded.
Hence it suffices to show $|f_1| + |f_2| + |f_3| \le \epsqd M$.

\begin{figure}[h]
  \begin{center}
    \includegraphics{qd_add_proof.eps}
    \caption{\label{qd_add_proof_fig}Quad-Double + Quad-Double}
  \end{center}
\end{figure}

First note that $|a_1| \le \eps M$, $|a_2| \le \eps^2 M$,and
$|a_3| \le \eps^3 M$, since the input expansions are assumed to be
normalized.  Similar inequalities applies for expansion $b$.
Applying Lemma \ref{two_sum_bound} to {\sc Two-Sum}s 1, 2, 3, 4, we obtain
\begin{displaymath}
  \begin{array}{rcl@{\qquad}rcl}
    |x_0| &\le& 2M & |e_0| &\le& 2\eps M\\
    |t_1| &\le& 2\eps M   & |e_1| &\le& 2\eps^2 M\\
    |t_2| &\le& 2\eps^2 M & |e_2| &\le& 2\eps^3 M\\
    |t_3| &\le& 2\eps^3 M & |e_3| &\le& 2\eps^4 M.
  \end{array}
\end{displaymath}

Now we can apply Lemma \ref{two_sum_bound} to {\sc Two-Sum} 5, to obtain
$|x_1| \le 4\eps M$ and $|u| \le 4 \eps^2 M$.  Then we apply Lemma
\ref{three_sum_bound} to {\sc Three-Sum} 6 to obtain
\begin{displaymath}
  \begin{array}{r@{\;\le\;}l}
    |x_2| & 16\eps^2 M \\
    |w| & 32 \eps^3 M  \\
    |v| & 32 \eps^4 M.
  \end{array}
\end{displaymath}

Applying Lemma \ref{three_sum_bound} to {\sc Three-Sum} 7, we have
\begin{displaymath}
  \begin{array}{r@{\;\le\;}l}
    |x_3| & 128\eps^3 M \\
    |z| & 256 \eps^4 M  \\
    |f_1| & 256 \eps^5 M.
  \end{array}
\end{displaymath}

Finally we apply Lemma \ref{three_sum_bound} again to {\sc Three-Sum} 8
to get
\begin{displaymath}
  \begin{array}{r@{\;\le\;}l}
    |x_4| & 1024\eps^4 M \\
    |f_2| & 2048 \eps^5 M  \\
    |f_3| & 2048 \eps^6 M.
  \end{array}
\end{displaymath}

Thus we have
\begin{displaymath}
  |f_1| + |f_2| + |f_3| \le 256 \eps^5 M + 2048 \eps^5 M + 2048 \eps^6 M
  \le 2305 \eps^5 M \le \epsqd M
\end{displaymath}
as claimed.
\end{proof}

\newpage
\bibliographystyle{plain}
\bibliography{qd}

\end{document}


\section{Introduction}

As a convenience to users, we provide a mechanism for declaring
nested coordinate systems.  This is particularly useful
for creating \emph{substructures} or \emph{subnets}.  Different
instances of a subnet may have the same relative placements
of nodes, but at different translations and orientations.

\section{Interface}

We support nested coordinate systems via a \emph{transformation stack}.
The entries in this stack data structures are all affine transformations that
take the current coordinate system to the global system.  New transformations
are \emph{composed} with the previous top-of-stack, so that if
$T_0$ is the current transformation to global coordinates and a
transformation $S$ is pushed onto the stack, then $T_0 S$ will
be the new transformation from current to global coordinates.

The transformation $T = Ax + b$ is given by a table of twelve entries
which represents the components of the matrix $[A; b]$ in column major
order.  A vector $x$ is given by a table with coordinate entries at
indices 1 to 3.  Note that the table can contain additional information
(e.g. a node name).  Part of the reason the transformation functions
overwrite the input vector table is so that entries besides those
at indices 1 to 3 can be retained unchanged.

The functions provided by this module are
\begin{itemize}
  \item {\tt{}xform{\char95}push(T)}: compose a transformation onto the stack
  \item {\tt{}xform{\char95}pop}: pop a level off the transformation stack
  \item {\tt{}top{\char95}xform(x)}: overwrite $x$ with $T_\mathit{top} x$,
        where $T_\mathit{top}$ is the top transform on the stack
  \item {\tt{}xform{\char95}apply(T,\ x)}: overwrite $x$ with $Tx$.
  \item {\tt{}xform{\char95}applyA(t,\ x)}: overwrite $x$ with $A_T x$,
        where $A_T$ is the linear part of the affine transform $T$.
  \item {\tt{}xform{\char95}compose(T,\ S)}: return $TS$
  \item {\tt{}xform{\char95}identity}: return the identity transform
  \item {\tt{}xform{\char95}ox(r),\ xform{\char95}oy(r),\ xform{\char95}oz(r)}:
        return right-handed rotations about the coordinate axes
  \item {\tt{}xform{\char95}translate(z)}: return a translation by the
        vector $z$
  \item {\tt{}subnet(f)}: return a function which creates a nested
        coordinate system according to any {\tt{}ox}, {\tt{}oy},
        and {\tt{}oz} parameters, calls {\tt{}f}, and then pops the
        nested coordinate system.
\end{itemize}

\section{Implementation}

\nwfilename{xformstack.nw}\nwbegincode{1}\sublabel{NWxfoD-xfoE-1}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-xfoE-1}}}\moddef{xformstack.lua~{\nwtagstyle{}\subpageref{NWxfoD-xfoE-1}}}\endmoddef
\LA{}data~{\nwtagstyle{}\subpageref{NWxfoD-dat4-1}}\RA{}
\LA{}functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}\RA{}
\nwnotused{xformstack.lua}\nwendcode{}\nwbegindocs{2}\nwdocspar

\subsection{The transform stack}

The size of the stack is maintained in the field $n$.

\nwenddocs{}\nwbegincode{3}\sublabel{NWxfoD-dat4-1}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-dat4-1}}}\moddef{data~{\nwtagstyle{}\subpageref{NWxfoD-dat4-1}}}\endmoddef
xform_stack = \{n = 0\};

\nwused{\\{NWxfoD-xfoE-1}}\nwendcode{}\nwbegindocs{4}\nwdocspar

Note that we compose new transformations onto the stack, interpreting
the transformation argument as a transformation into the current coordinates
instead of a transformation into the global coordinates.

\nwenddocs{}\nwbegincode{5}\sublabel{NWxfoD-fun9-1}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\endmoddef
function xform_push(T)
  local n = xform_stack.n + 1
  if n == 1 then
    xform_stack[n] = T
  else
    xform_stack[n] = xform_compose(xform_stack[n-1], T);
  end
  xform_stack.n = n;
end

\nwalsodefined{\\{NWxfoD-fun9-2}\\{NWxfoD-fun9-3}\\{NWxfoD-fun9-4}\\{NWxfoD-fun9-5}\\{NWxfoD-fun9-6}\\{NWxfoD-fun9-7}\\{NWxfoD-fun9-8}\\{NWxfoD-fun9-9}\\{NWxfoD-fun9-A}\\{NWxfoD-fun9-B}\\{NWxfoD-fun9-C}}\nwused{\\{NWxfoD-xfoE-1}}\nwendcode{}\nwbegindocs{6}\nwdocspar

\nwenddocs{}\nwbegincode{7}\sublabel{NWxfoD-fun9-2}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-2}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
function xform_pop()
  xform_stack.n = xform_stack.n - 1
end

\nwendcode{}\nwbegindocs{8}\nwdocspar

\nwenddocs{}\nwbegincode{9}\sublabel{NWxfoD-fun9-3}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-3}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
function top_xform(x)
  local n = xform_stack.n
  if n > 0 then
    return xform_apply(xform_stack[n], x)
  else
    return x
  end
end

\nwendcode{}\nwbegindocs{10}\nwdocspar

\subsection{Transformation functions}

\nwenddocs{}\nwbegincode{11}\sublabel{NWxfoD-fun9-4}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-4}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Overwrite x with Tx
function xform_apply(T, x)
  local y1 = T[1]*x[1] + T[4]*x[2] + T[7]*x[3] + T[10];
  local y2 = T[2]*x[1] + T[5]*x[2] + T[8]*x[3] + T[11];
  local y3 = T[3]*x[1] + T[6]*x[2] + T[9]*x[3] + T[12];
  x[1] = y1;
  x[2] = y2;
  x[3] = y3;
  return x;
end

\nwendcode{}\nwbegindocs{12}\nwdocspar

\nwenddocs{}\nwbegincode{13}\sublabel{NWxfoD-fun9-5}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-5}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Overwrite x with A_T * x
function xform_applyA(T, x)
  local y1 = T[1]*x[1] + T[4]*x[2] + T[7]*x[3];
  local y2 = T[2]*x[1] + T[5]*x[2] + T[8]*x[3];
  local y3 = T[3]*x[1] + T[6]*x[2] + T[9]*x[3];
  x[1] = y1;
  x[2] = y2;
  x[3] = y3;
  return x;
end

\nwendcode{}\nwbegindocs{14}\nwdocspar

Recall that
\[
  T(S(x)) = A_T (A_S x + b_S) + b_T = (A_T A_S) x + T(b_T)
\]

\nwenddocs{}\nwbegincode{15}\sublabel{NWxfoD-fun9-6}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-6}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Return TS
function xform_compose(T, S)
  local TS = \{\};
  for k = 1,4 do
    local base = 3*k-3;
    TS[base+1] = T[1]*S[base+1] + T[4]*S[base+2] + T[7]*S[base+3];
    TS[base+2] = T[2]*S[base+1] + T[5]*S[base+2] + T[8]*S[base+3];
    TS[base+3] = T[3]*S[base+1] + T[6]*S[base+2] + T[9]*S[base+3];
  end
  TS[10] = TS[10] + T[10];
  TS[11] = TS[11] + T[11];
  TS[12] = TS[12] + T[12];
  return TS;
end

\nwendcode{}\nwbegindocs{16}\nwdocspar

\nwenddocs{}\nwbegincode{17}\sublabel{NWxfoD-fun9-7}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-7}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Return the identity
function xform_identity()
  return \{ 1, 0, 0,
           0, 1, 0,
           0, 0, 1,
           0, 0, 0 \};
end

\nwendcode{}\nwbegindocs{18}\nwdocspar

Getting right hand rotations correct is always a trick.
Important note -- remember that the transformation matrix is
interpreted as column-major, but is ``typographically'' row
major.  So put on your transposing hat before reading the
following three functions.

\nwenddocs{}\nwbegincode{19}\sublabel{NWxfoD-fun9-8}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-8}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Return a rotation about the x axis
function xform_ox(r)
  local c = cos(r)
  local s = sin(r)
  return \{ 1,   0,  0,
           0,   c,  s,
           0,  -s,  c,
           0,   0,  0 \}
end

\nwendcode{}\nwbegindocs{20}\nwdocspar

\nwenddocs{}\nwbegincode{21}\sublabel{NWxfoD-fun9-9}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-9}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Return a rotation about the y axis
function xform_oy(r)
  local c = cos(r)
  local s = sin(r)
  return \{ c,   0, -s,
           0,   1,  0,
           s,   0,  c,
           0,   0,  0 \}
end

\nwendcode{}\nwbegindocs{22}\nwdocspar

\nwenddocs{}\nwbegincode{23}\sublabel{NWxfoD-fun9-A}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-A}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Return a rotation about the z axis
function xform_oz(r)
  local c = cos(r)
  local s = sin(r)
  return \{ c,   s,  0,
          -s,   c,  0,
           0,   0,  1,
           0,   0,  0 \}
end

\nwendcode{}\nwbegindocs{24}\nwdocspar

\nwenddocs{}\nwbegincode{25}\sublabel{NWxfoD-fun9-B}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-B}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
-- Return a translation
function xform_translate(z)
  return \{ 1,    0,    0,
           0,    1,    0,
           0,    0,    1,
           z[1], z[2], z[3] \}
end

\nwendcode{}\nwbegindocs{26}\nwdocspar

\subsection{{\tt{}node} and {\tt{}subnetize} functions}

We assume that node positions are expressed in the current coordinate
system (at least, that's what we assume for most purposes).
So the {\tt{}nodex} (``node transformed'') function transforms
the input coordinates from local to global, and them makes a node.

We still want to leave the option of expressing node coordinates
directly in the global coordinate system, though.  For instance,
we may want to put a node halfway between two other nodes which
have already been transformed into global coordinates.  For this
reason, we leave the {\tt{}node} function alone.

\nwenddocs{}\nwbegincode{27}\sublabel{NWxfoD-fun9-C}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-fun9-C}}}\moddef{functions~{\nwtagstyle{}\subpageref{NWxfoD-fun9-1}}}\plusendmoddef
function nodex(p)
  if p[1] then
    top_xform(p)
  end
  return node(p)
end

\nwendcode{}\nwbegindocs{28}\nwdocspar

\subsection{Test code}

\nwenddocs{}\nwbegincode{29}\sublabel{NWxfoD-xfoC-1}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-xfoC-1}}}\moddef{xformtst.lua~{\nwtagstyle{}\subpageref{NWxfoD-xfoC-1}}}\endmoddef
use("xformstack.lua")

\LA{}test transform constructors~{\nwtagstyle{}\subpageref{NWxfoD-tesR-1}}\RA{}
\LA{}test composition~{\nwtagstyle{}\subpageref{NWxfoD-tesG-1}}\RA{}
\nwnotused{xformtst.lua}\nwendcode{}\nwbegindocs{30}\nwdocspar

\nwenddocs{}\nwbegincode{31}\sublabel{NWxfoD-tesR-1}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-tesR-1}}}\moddef{test transform constructors~{\nwtagstyle{}\subpageref{NWxfoD-tesR-1}}}\endmoddef
-- First check out the basics

rx45 = xform_ox(45)
ry45 = xform_oy(45)
rz45 = xform_oz(45)
trans = xform_translate \{1, 2, 3\}

x1 = xform_apply(rx45,  \{1, 0, 0\})
x2 = xform_apply(ry45,  \{1, 0, 0\})
x3 = xform_apply(rz45,  \{1, 0, 0\})
x4 = xform_apply(trans, \{1, 0, 0\})
x5 = xform_applyA(trans, \{1, 0, 0\})

print("Rotate e1 by rx45: ",     x1[1], x1[2], x1[3])
print("Rotate e1 by ry45: ",     x2[1], x2[2], x2[3])
print("Rotate e1 by rz45: ",     x3[1], x3[2], x3[3])
print("Translate e1 by 1,2,3: ", x4[1], x4[2], x4[3])
print("Apply A e1 by 1,2,3: ",   x5[1], x5[2], x5[3])

\nwused{\\{NWxfoD-xfoC-1}}\nwendcode{}\nwbegindocs{32}\nwdocspar

\nwenddocs{}\nwbegincode{33}\sublabel{NWxfoD-tesG-1}\nwmargintag{{\nwtagstyle{}\subpageref{NWxfoD-tesG-1}}}\moddef{test composition~{\nwtagstyle{}\subpageref{NWxfoD-tesG-1}}}\endmoddef
-- Now check out composition

T = xform_compose(trans, rz45)
x = xform_apply(T, \{1, 0, 0\})

print("Rotate then translate: ", x[1], x[2], x[3])

undoT = xform_compose(xform_oz(-45), xform_translate\{-1,-2,-3\})
xform_apply(undoT, x)

print("After undo operation: ", x[1], x[2], x[3])

\nwused{\\{NWxfoD-xfoC-1}}\nwendcode{}

\nwixlogsorted{c}{{data}{NWxfoD-dat4-1}{\nwixu{NWxfoD-xfoE-1}\nwixd{NWxfoD-dat4-1}}}%
\nwixlogsorted{c}{{functions}{NWxfoD-fun9-1}{\nwixu{NWxfoD-xfoE-1}\nwixd{NWxfoD-fun9-1}\nwixd{NWxfoD-fun9-2}\nwixd{NWxfoD-fun9-3}\nwixd{NWxfoD-fun9-4}\nwixd{NWxfoD-fun9-5}\nwixd{NWxfoD-fun9-6}\nwixd{NWxfoD-fun9-7}\nwixd{NWxfoD-fun9-8}\nwixd{NWxfoD-fun9-9}\nwixd{NWxfoD-fun9-A}\nwixd{NWxfoD-fun9-B}\nwixd{NWxfoD-fun9-C}}}%
\nwixlogsorted{c}{{test composition}{NWxfoD-tesG-1}{\nwixu{NWxfoD-xfoC-1}\nwixd{NWxfoD-tesG-1}}}%
\nwixlogsorted{c}{{test transform constructors}{NWxfoD-tesR-1}{\nwixu{NWxfoD-xfoC-1}\nwixd{NWxfoD-tesR-1}}}%
\nwixlogsorted{c}{{xformstack.lua}{NWxfoD-xfoE-1}{\nwixd{NWxfoD-xfoE-1}}}%
\nwixlogsorted{c}{{xformtst.lua}{NWxfoD-xfoC-1}{\nwixd{NWxfoD-xfoC-1}}}%
\nwbegindocs{34}\nwdocspar

\nwenddocs{}


\documentclass[main.tex]{subfiles}
\begin{document}

\marginpar{Wednesday\\ 2020-11-18, \\ compiled \\ \today}

Recall that
%
\begin{align}
\Sigma = \num{5.2} \alpha^{-4/5} \dot{M}_{16}^{7/10} M^{1/4} R^{-3/4} \SI{}{g / cm^2}
\,.
\end{align}

Is it true that \(M_d = M _{\text{disk}} \ll M\), as we assumed?
We can calculate it as
%
\begin{align}
M_d &= \int_{R _{\text{in}}}^{R _{\text{max}}} 2 \pi R \Sigma \dd{R}  \\
&\approx \num{e-8} \alpha^{-4/5} M_{16}^{7/10} M^{1/2} M_{\odot}
\,,
\end{align}
%
assuming that \(R _{\text{max}} \approx 10 R _{\text{in}}\).
This is indeed many orders of magnitude below the mass of the stellar source.

\subsubsection{Regions of the disk}

The \(\alpha \) parameter comes from the very rough assumption \(\nu _{\text{turb}} = \alpha c_s H\), it is a weak point of this model.
Asking that \(\alpha = \const\) is just plain wrong.

Further, we assumed that \(P = P _{\text{gas}}\), and that the Rosseland mean opacity \(\kappa _R\) is only given by free-free absorption.

We know that for Thompson scattering the cross-section is \(\kappa _R^{s} = \sigma _T / m_p = \SI{.4}{cm^2 / g}\).
When is this smaller than the free-free opacity? In dimensionless terms, the equation for \(\kappa = \tau / \Sigma \) reads
%
\begin{align}
\kappa_{R}^{\text{ff}} &> \kappa_R^{s} \\
\num{6.3} \dot{M}_{16}^{-1/2} M^{1/4} R_{10}^{-3/4} f^2 &> \num{.4}  \\
R_{10} &> \num{.5e-2} \dot{M}_{16}^{2/3} M^{1/3} f^{8/3} \\
R &> \num{.5e8} \dot{M}_{16}^{2/3} M^{1/3} f^{8/3} \SI{}{cm}
\,.
\end{align}

For a white dwarf, this is always the case; we can tell in general that for \(R \lesssim \SI{e8}{cm}\) electron scattering dominates.

The temperature decreases with radius as \(T \propto R^{-3/2}\), so for high enough radii it can drop below \SI{e4}{K}, at which point recombination can occur: at that point free-free absorption cannot occur anymore, and we must account for free-bound and bound-bound transitions.

If a NS or a BH is accreting, on the other hand, we can have a scattering-dominated internal region.

So, in terms of the \textbf{main type of matter-radiation interaction} we will have three regions: going outwards, there is domination of electron scattering, free-free absorption, bound-free/bound-bound absorption.

Does \(P _{\text{gas}}\) dominate over \(P _{\text{rad}}\)? their ratio is indeed
%
\begin{align}
\frac{P _{\text{rad}}}{P _{\text{gas}}} = \frac{ \frac{1}{3} a T^{4}}{\frac{k T_c \Sigma H}{\mu m_p}} \approx \num{3e-3} \alpha^{1/10} \dot{M}_{16}^{7/10} R_{10}^{-3/8} f^{7/5} \ll 1
\,.
\end{align}

As \(R\) decreases, \(P _{\text{rad}}\) becomes ever more relevant.
Is there an equality radius? It will definitely be smaller than \SI{3e8}{cm}.
Doing the calculation, we find
%
\begin{align}
R  _{\text{equality}} \approx \num{24} \alpha^{2/21} \dot{M}_{16}^{16/21} f^{9/21} \SI{}{km}
\,.
\end{align}

This may sometimes be attained in the innermost region of the disk, right before the ISCO.

So, in terms of the \textbf{nature of most of the pressure}, we may have a radiation-dominated region in the innermost part of the disk, but mostly there will be gas pressure domination.

\paragraph{The shape of the disk}

We calculate the shape of the disk, \(H(R)\), in the innermost radiation-dominated region.
The sound speed under radiation domination is
%
\begin{align}
c_s^2 = \frac{P}{\rho } = \frac{1}{3} \frac{a T_c^{4}}{\rho} = \frac{1}{3} \frac{4 \sigma }{c} \frac{T_c^{4}}{\rho }
\,,
\end{align}
%
and we know that
%
\begin{align}
\frac{4}{3} \frac{\sigma T_c^{4}}{\tau } = \frac{3 GM \dot{M}}{8 \pi R^3} f
\,,
\end{align}
%
which means that
%
\begin{align}
c_s^2 = \frac{3 GM \dot{M} \tau f}{8 \pi R^3 \rho c}
\,,
\end{align}
%
and using the fact that, for scattering opacity domination,
%
\begin{align}
\tau = \kappa _R^{s} \Sigma = \frac{\sigma _T}{m_p} \rho H
\,,
\end{align}
%
we find
%
\begin{align}
c_s^2 =
\frac{3 GM \dot{M} \sigma _T \rho H f}{8 \pi R^3 \rho  c m_p} =
\frac{3 GM \dot{M} \sigma _T  H f}{8 \pi R^3   c m_p}
\,,
\end{align}
%
but we also know that \(H = c_s R (R / GM)^{1/2}\); using this fact we can calculate the sound speed \(c_s = (H/R)(GM/R)^{1/2} \).
Using this (see equation \eqref{eq:speed-of-sound-disk-shape}), we get
%
\begin{align}
\frac{H^2}{R^2} \frac{GM}{R} &= \frac{3 GM \dot{M} \sigma _T  H f}{8 \pi R^3   c m_p} \\
H &= \frac{3 \sigma _T \dot{M} }{8 \pi c m_p}f
\,,
\end{align}
%
which is nearly independent of \(R\): the only dependence is inside the factor \(f\), which depends on \(R\) quite weakly.
The shape of the disk is slab-like in the inner region, and concave in the outer part but still quite flat.

\paragraph{The Eddington limit}

The Eddington luminosity for electron scattering is
%
\begin{align}
L _{\text{Edd}} = \frac{4 \pi G M m_p c}{\sigma _T}
\,,
\end{align}
%
and the corresponding accretion rate is \(\dot{M} _{\text{Edd}} = L _{\text{Edd}} / c^2\).

The critical accretion rate is the one which produces an Eddington luminosity, after accounting for efficiency:
%
\begin{align}
\eta \dot{M} _{\text{crit}} c^2 = L _{\text{Edd}}
\,,
\end{align}
%
so \(\dot{M} _{\text{crit}}\) is larger than \(\dot{M} _{\text{Edd}}\).
Using this, the height of the disk is given by
%
\begin{align}
H &= \frac{3}{2} \dot{M} f \frac{\sigma _T}{4 \pi c m_p } = \frac{3}{2} \dot{M} f \frac{GM}{L _{\text{Edd}}} \\
&= \frac{3}{2} \underbrace{\frac{GM}{R _{\text{in}}c^2}}_{\eta } R _{\text{in}} \frac{\dot{M}}{\dot{M} _{\text{Edd}}} f  \\
&= \frac{3}{2} \eta R _{\text{in}} \frac{\dot{M}}{\dot{M} _{\text{Edd}}} f
\,,
\end{align}
%
so
%
\begin{align}
\frac{H}{R _{\text{in}}} = \frac{3}{2} \frac{\dot{M}}{\dot{M} _{\text{crit}}} f
\,,
\end{align}
%
and we can see that \(H < R _{\text{in}}\) iff \(\dot{M} < M _{\text{crit}}\).
Then, we see that \textbf{the accretion rate must be subcritical as long as we want to keep the disk thin}.

\subsection{The multicolor blackbody}

A final point about disks: each layer of the disk emits roughly a blackbody, which means that the total spectrum is a superposition of several blackbodies, this is called a multicolor blackbody.

The spectrum emitted by each annulus, as usual, is described by a  Planck function:
%
\begin{align}
I_\nu = \frac{2h}{c^2} \frac{\nu^3}{\exp(\frac{h \nu }{k_B T}) - 1}
\,,
\end{align}
%
as long as there is no reprocessing of the radiation from stuff around the disk.
This is an interesting process, but for simplicity we will not discuss it.

What we measure is the flux:
%
\begin{align}
F_\nu = \int_{4 \pi } I_\nu \cos \theta \dd{\Omega }
\,,
\end{align}
%
where \(\dd{\Omega } = 2 \pi R \dd{R}/D^2\), where \(D\) is the distance from us.
The integral to compute is
%
\begin{align}
F_\nu = \frac{2 \pi }{D^2} \cos \iota \int_{R _{\text{in}}}^{R _{\text{out}}} R \dd{R} \frac{\nu^3}{\exp(\frac{h \nu }{k_B T(R)}) - 1}
\,.
\end{align}

This integral can be computed numerically, but we can already gather its main characteristics.
As we have seen earlier \eqref{eq:temperature-accretion-disk}, the temperature looks like
%
\begin{align}
T(R) = T _{\text{in}} \qty( \frac{R _{\text{in}}}{R})^{3/4}
\,.
\end{align}

Let us now estimate the integral in three limits, comparing \(h \nu     \) to \(k_B T(R _{\text{in}})\) and \(k_B T (R _{\text{out}})\) respectively.

The first interesting limit is the low-energy one: \(h \nu \ll k_B T (R _{\text{out}}) < k_B T(R)\) for any \(R\).
Then, the flux is proportional to
%
\begin{align}
F_\nu \propto \int R \dd{R} \frac{\nu^3}{h \nu / k_B T(R)}
\propto \nu^2 \int T(R) R \dd{R}
\propto \nu^2
\,.
\end{align}

The opposite, high energy limit \(h \nu \gg k_B T(R _{\text{in}})\) yields an exponential cutoff, since the contribution of the exponential \(e^{-h \nu / k_B T(R)}\) of the term in the integral with \(T = T _{\text{in}}\) is dominant
%
\begin{align}
F_\nu \propto \nu^3 \exp(- \frac{h \nu }{k_B T _{\text{in}}})
\,.
\end{align}

In the intermediate region, \(k_B T _{\text{out}} < h \nu < k_B T _{\text{in}}\).

Defining \(x = h \nu / k_B T(R)\), we find
%
\begin{align}
F_\nu \propto \int \frac{\nu^3 }{e^{x} - 1} R \dd{R}
\,,
\end{align}
%
but \(x \propto \nu / T \propto \nu R^{3/4}\), therefore \(R \propto x^{4/3} \nu^{-4/3}\), which means that (since \(\nu \) is constant in the context of the integral) \(\dd{R} \propto x^{1/3} \nu^{-4/3} \dd{x}\)
%
\begin{align}
F_\nu \propto \int \frac{\nu^3 \nu^{-8/3}}{e^{x}-1} x^{5/3} \dd{x}
\,,
\end{align}
%
which means that
%
\begin{align}
F_\nu \propto \nu^{1/3} \int \frac{x^{5/3}}{e^{x}-1} \dd{x}
\,.
\end{align}

The integral is approximately one from 0 to \(\infty \), a number.
The \(F \propto \nu^{1/3}\) signature intermediate region is a characteristic of accretion disks.

\end{document}


\subsection{Data field values}
\label{subsec:library_of_transformations:instance_level_transformations:data_field_values}

\begin{figure}
    \centering
    \begin{subfigure}{0.45\textwidth}
        \centering
        \includegraphics{images/05_library_of_transformations/03_instance_level_transformations/06_data_field_values/data_field_value.pdf}
        \caption{$Im_{DataField}$ with one object and string value ``some value''}
        \label{fig:library_of_transformations:instance_level_transformations:data_field_values:visualisation:ecore}
    \end{subfigure}
    \begin{subfigure}{0.45\textwidth}
        \centering
        \input{images/05_library_of_transformations/03_instance_level_transformations/06_data_field_values/data_field_as_edge_type_value.tikz}
        \caption{$IG_{DataField}$ with one node and string value ``some value''}
        \label{fig:library_of_transformations:instance_level_transformations:data_field_values:visualisation:groove}
    \end{subfigure}
    \caption{Visualisation of the transformation of field values from fields typed by data types}
    \label{fig:library_of_transformations:instance_level_transformations:data_field_values:visualisation}
\end{figure}

The previous sections have shown the instance level transformations of the introduction of all kinds of types and their instances. From this section onward, these types and their instances will be enriched by introducing fields. In this section, the instance level transformation belonging to the transformation of a data field is discussed. The type level transformation for data fields can be found in \cref{subsec:library_of_transformations:type_level_transformations:data_fields}. On the instance level, values for the data fields are introduced.

\begin{defin}[Instance model $Im_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field}
Let $Im_{DataField}$ be an instance model typed by $Tm_{DataField}$ (\cref{defin:library_of_transformations:type_level_transformations:data_fields:tmod_data_field}). Define a set $objects$, which represent the objects that will get a value for the field introduced by $Tm_{DataField}$. Furthermore, define a function $obids$ which maps each of these objects to their corresponding identifier and a function $values$, which maps each of these objects to its value for the field introduced by $Tm_{DataField}$. $Im_{DataField}$ is defined as:
\begin{align*}
Object =\ &objects \\
\mathrm{ObjectClass} =\ & \begin{cases}
    (ob, classtype) & \mathrm{if }\ ob \in objects
\end{cases}\\
\mathrm{ObjectId} =\ & \begin{cases}
    (ob, obids(ob)) & \mathrm{if }\ ob \in objects
\end{cases}\\
\mathrm{FieldValue} =\ & \begin{cases}
    ((ob, (classtype, name)), values(ob)) & \mathrm{if }\ ob \in objects
\end{cases} \\
\mathrm{DefaultValue} =\ & \{\}
\end{align*}
\isabellelref{imod_data_field}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{defin}

\begin{thm}[Correctness of $Im_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field_correct}
$Im_{DataField}$ (\cref{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field}) is a valid instance model in the sense of \cref{defin:formalisations:ecore_formalisation:instance_models:model_validity}.
\isabellelref{imod_data_field_correct}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{thm}

A visual representation of $Im_{DataField}$ with $objects = \{ob\}$ and $obids(ob) = someId$ can be seen in \cref{fig:library_of_transformations:instance_level_transformations:data_field_values:visualisation:ecore}. In this visualisation, the field value for $ob$ is defined as $values(ob) = \text{``some value''}$. Although this visualisation only shows one object, it is required to define a value for all objects that contain the field. Failing to do so would result in an invalid instance model after it is combined with another model, as the next definition will show. The correctness proof of $Im_{DataField}$ only is already quite involved, but not be included here for conciseness. It can be found as part of the validated Isabelle proofs.

In order to make composing transformation functions possible, $Im_{DataField}$ should be compatible with the instance model it is combined with.

\begin{thm}[Correctness of $\mathrm{combine}(Im, Im_{DataField})$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field_combine_correct}
Assume an instance model $Im$ that is valid in the sense of \cref{defin:formalisations:ecore_formalisation:instance_models:model_validity}. Then $Im$ is compatible with $Im_{DataField}$ (in the sense of \cref{defin:transformation_framework:instance_models_and_instance_graphs:combining_instance_models:compatibility}) if:
\begin{itemize}
    \item All requirements of \cref{defin:library_of_transformations:type_level_transformations:data_fields:tmod_data_field_combine_correct} are met, to ensure the combination of the corresponding type models is valid;
    \item The class type on which the field is defined by $Tm_{DataField}$ may not be extended by another class type in the type model corresponding to $Im$;
    \item All of the objects in the set $objects$ must already be objects in $Im$;
    \item All objects typed by the class type on which the field is defined must occur in the set $objects$ and thus have a value in $Im_{DataField}$;
    \item For all of the objects in the set $objects$, the identifier set by $obids$ must be the same identifier as set by $Im$ for that object;
    \item For all objects in set $objects$, the value set by the $values$ function must be valid.
\end{itemize}
\isabellelref{imod_data_field_combine_correct}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{thm}

\begin{proof}
Use \cref{defin:transformation_framework:instance_models_and_instance_graphs:combining_instance_models:imod_combine_merge_correct}. It is possible to show that all assumptions hold. Now we have shown that $\mathrm{combine}(Im, Im_{DataField})$ is consistent in the sense of \cref{defin:formalisations:ecore_formalisation:instance_models:model_validity}.
\end{proof}

As explained earlier, $Im_{DataField}$ needs to introduce values for all objects that are typed by the class type on which the field is defined. This is enforced by the requirements of \cref{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field_combine_correct}. The proof is not included here for conciseness, but can be found as part of the validated proofs in Isabelle.

The definitions and theorems for introducing values for fields of data types within Ecore are now complete.

\subsubsection{Encoding as edges and nodes}

In the type level transformation of data fields, data fields were encoded in GROOVE as edge types to an primitive type. On the instance level, this edge type will be used and edges will be created to give a value to each node type that has the field defined. The encoding corresponding to $Im_{DataField}$ can then be represented as $IG_{DataField}$, defined in the following definition:

\begin{defin}[Instance graph $IG_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:ig_data_field_as_edge_type}
Let $IG_{DataField}$ be the instance graph typed by type graph $TG_{DataField}$ (\cref{defin:library_of_transformations:type_level_transformations:data_fields:tg_data_field_as_edge_type}). Reuse the set $objects$ from $Im_{DataField}$. Moreover, reuse the functions $obids$ and $values$ from $Im_{DataField}$.
The objects in the set $objects$ are converted to nodes in $Im_{DataField}$. For each of these objects, an edge of the encoded field is created. This edge targets a node that corresponds to the value set by $values$ for the corresponding object. Finally, the identity of the objects is defined using $obids$. $IG_{DataField}$ is defined as:
\begin{align*}
N =\ & objects \cup \{values(ob) \mid ob \in objects\} \\
E =\ & \big\{\big(ob, (\mathrm{ns\_\!to\_\!list}(classtype), \langle name \rangle, fieldtype), values(ob)\big) \mid ob \in objects \big\} \\
\mathrm{ident} =\ & \begin{cases}
    (obids(ob), ob) & \mathrm{if }\ ob \in objects
\end{cases}
\end{align*}
with
\begin{align*}
\mathrm{type}_n =\ & \begin{cases}
    (ob, \mathrm{ns\_\!to\_\!list}(classtype)) & \mathrm{if }\ ob \in objects
\end{cases}
\end{align*}
\isabellelref{ig_data_field_as_edge_type}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{defin}

\begin{thm}[Correctness of $IG_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:ig_data_field_as_edge_type_correct}
$IG_{DataField}$ (\cref{defin:library_of_transformations:instance_level_transformations:data_field_values:ig_data_field_as_edge_type}) is a valid instance graph in the sense of \cref{defin:formalisations:groove_formalisation:instance_graphs:instance_graph_validity}.
\isabellelref{ig_data_field_as_edge_type_correct}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{thm}

A visual representation of $IG_{DataField}$ with $objects = \{ob\}$ and $obids(ob) = someId$ can be seen in \cref{fig:library_of_transformations:instance_level_transformations:data_field_values:visualisation:groove}. Like the previous visualisation, the field value for $ob$ is defined as $values(ob) = \text{``some value''}$. Although this visualisation only shows one node, it is required to define a value for all nodes typed by the node type corresponding to the field. Failing to do so would result in an invalid instance graph after it is combined with another graph, as the next definition will show. The correctness proof of $IG_{DataField}$ only is already quite involved, but not be included here for conciseness. It can be found as part of the validated Isabelle proofs.

In order to make composing transformation functions possible, $IG_{DataField}$ should be compatible with the instance graph it is combined with.

\begin{thm}[Correctness of $\mathrm{combine}(IG, IG_{DataField})$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:ig_data_field_as_edge_type_combine_correct}
Assume an instance graph $IG$ that is valid in the sense of \cref{defin:formalisations:groove_formalisation:instance_graphs:instance_graph_validity}. Then $IG$ is compatible with $IG_{DataField}$ (in the sense of \cref{defin:transformation_framework:instance_models_and_instance_graphs:combining_instance_graphs:compatibility}) if:
\begin{itemize}
    \item All requirements of \cref{defin:library_of_transformations:type_level_transformations:data_fields:tg_data_field_as_edge_type_combine_correct} are met, to ensure the combination of the corresponding type graphs is valid;
    \item The node type on which the corresponding field is defined is not extended by other node types within the type graph corresponding to $IG$;
    \item All nodes in $IG$ that are typed by the node type on which the field is defined are also nodes in $IG_{DataField}$;
    \item For all nodes shared between $IG$ and $IG_{DataField}$, each node must have the same identifier in both $IG$ and $IG_{DataField}$;
    \item For all nodes for which the field is set, the $values$ function must define a valid value;
    \item If an primitive type has incoming or outgoing edge types in the type graph corresponding to $IG$, then the lower multiplicity of these edge types must be 0.
\end{itemize}
\isabellelref{ig_data_field_as_edge_type_combine_correct}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{thm}

\begin{proof}
Use \cref{defin:transformation_framework:instance_models_and_instance_graphs:combining_instance_graphs:ig_combine_merge_correct}. It is possible to show that all assumptions hold. Now we have shown that $\mathrm{combine}(IG, IG_{DataField})$ is valid in the sense of \cref{defin:formalisations:groove_formalisation:instance_graphs:instance_graph_validity}.
\end{proof}

Like the definition for the combination of instance models, the combination of instance graphs also requires the user to set a value for all nodes that are typed by the node type that corresponds to the field type. This is to keep the graph valid.

The next definitions define the transformation function from $Im_{DataField}$ to $IG_{DataField}$:

\begin{defin}[Transformation function $f_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field_to_ig_data_field_as_edge_type}
The transformation function $f_{DataField}(Im)$ is defined as:
\begin{align*}
N =\ & Object_{Im} \cup \{values(ob) \mid ob \in Object_{Im}\}  \\
E =\ & \big\{\big(ob, (\mathrm{ns\_\!to\_\!list}(classtype), \langle name \rangle, fieldtype), values(ob)\big) \mid ob \in Object_{Im} \big\} \\
\mathrm{ident} =\ & \begin{cases}
    (obids(ob), ob) & \mathrm{if }\ ob \in Object_{Im}
\end{cases}
\end{align*}
with
\begin{align*}
\mathrm{type}_n =\ & \begin{cases}
    (ob, \mathrm{ns\_\!to\_\!list}(name)) & \mathrm{if }\ ob \in Object_{Im}
\end{cases}
\end{align*}
\isabellelref{imod_data_field_to_ig_data_field_as_edge_type}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{defin}

\begin{thm}[Correctness of $f_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field_to_ig_data_field_as_edge_type_func}
$f_{DataField}(Im)$ (\cref{defin:library_of_transformations:instance_level_transformations:data_field_values:imod_data_field_to_ig_data_field_as_edge_type}) is a valid transformation function in the sense of \cref{defin:transformation_framework:instance_models_and_instance_graphs:combining_transformation_functions:transformation_function_instance_model_instance_graph} transforming $Im_{DataField}$ into $IG_{DataField}$.
\isabellelref{imod_data_field_to_ig_data_field_as_edge_type_func}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{thm}

The proof of the correctness of $f_{DataField}$ will not be included here. Instead, it can be found in the validated Isabelle theories.

Finally, to complete the transformation, the transformation function that transforms $IG_{DataField}$ into $Im_{DataField}$ is defined:

\begin{defin}[Transformation function $f'_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:ig_data_field_as_edge_type_to_imod_data_field}
The transformation function $f'_{DataField}(IG)$ is defined as:
\begin{align*}
Object =\ &\{\mathrm{src}(e) \mid e \in E_{IG}\} \\
\mathrm{ObjectClass} =\ & \begin{cases}
    (ob, classtype) & \mathrm{if }\ ob \in \{\mathrm{src}(e) \mid e \in E_{IG}\}
\end{cases}\\
\mathrm{ObjectId} =\ & \begin{cases}
    (ob, obids(ob)) & \mathrm{if }\ ob \in \{\mathrm{src}(e) \mid e \in E_{IG}\}
\end{cases}\\
\mathrm{FieldValue} =\ & \begin{cases}
    ((ob, (classtype, name)), values(ob)) & \mathrm{if }\ ob \in \{\mathrm{src}(e) \mid e \in E_{IG}\}
\end{cases} \\
\mathrm{DefaultValue} =\ & \{\}
\end{align*}
\isabellelref{ig_data_field_as_edge_type_to_imod_data_field}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{defin}

\begin{thm}[Correctness of $f'_{DataField}$]
\label{defin:library_of_transformations:instance_level_transformations:data_field_values:ig_data_field_as_edge_type_to_tmod_class_func}
$f'_{DataField}(IG)$ (\cref{defin:library_of_transformations:instance_level_transformations:data_field_values:ig_data_field_as_edge_type_to_imod_data_field}) is a valid transformation function in the sense of \cref{defin:transformation_framework:instance_models_and_instance_graphs:combining_transformation_functions:transformation_function_instance_graph_instance_model} transforming $IG_{DataField}$ into $Im_{DataField}$.
\isabellelref{ig_data_field_as_edge_type_to_imod_data_field_func}{Ecore-GROOVE-Mapping-Library.DataFieldValue}
\end{thm}

Once more, the correctness proof is not included here but can be found in the validated Isabelle proofs of this thesis.


\chapter{Graphs}

\textbf{Erdos-Gallai:} $d_1\geq\cdots\geq d_n$ can be degree sequence of simple graph on $n$ vertices iff their sum is even and $\sum_{i=1}^{k}d_{i}\leq k(k-1)+\sum _{i=k+1}^{n}\min(d_{i},k), \forall 1\le k\le n.$

\section{Cycles}
	\kactlimport{Basics/DirectedCycle.h}
	\kactlimport{Basics/NegativeCycle (7.3).h}

\section{DSU}
	\kactlimport{DSU/DSU (7.6).h}

\section{Trees}
	\kactlimport{Trees (10)/LCAjump (10.2).h}
	\kactlimport{Trees (10)/LCArmq (10.2).h}
	\kactlimport{Trees (10)/HLD (10.3).h}
	\kactlimport{Trees (10)/Centroid (10.3).h}

	\subsection{SqrtDecompton}

		HLD generally suffices. If not, here are some common strategies:

		\begin{itemize}
			\item Rebuild the tree after every $\sqrt N$ queries. % https://codeforces.com/contest/1254/submission/65439802
			\item Consider vertices with $>$ or $<\sqrt N$ degree separately. % https://codeforces.com/contest/1254/submission/65437007
			\item For subtree updates, note that there are $O(\sqrt N)$ distinct sizes among child subtrees of any node.
		\end{itemize}

		\textbf{Block Tree:} Use a DFS to split edges into contiguous groups of size $\sqrt N$ to $2\sqrt N.$

		\textbf{Mo's Algorithm for Tree Paths:} Maintain an array of vertices where each one appears twice, once when a DFS enters the vertex (\texttt{st}) and one when the DFS exists (\texttt{en}). For a tree path $u\leftrightarrow v$ such that \texttt{st[u]<st[v]},

		\begin{itemize}
		\item If $u$ is an ancestor of $v,$ query \texttt{[st[u],st[v]]}.
		\item Otherwise, query $\texttt{[en[u],st[v]]}$ and consider $LCA(u,v)$ separately.
		\end{itemize}

		Solutions with worse complexities can be faster if you optimize the operations that are performed most frequently. Use arrays instead of vectors whenever possible. Iterating over an array in order is faster than iterating through the same array in some other order (ex. one given by a random permutation) or DFSing on a tree of the same size. Also, the difference between $\sqrt N$ and the optimal block (or buffer) size can be quite large. Try up to 5x smaller or larger (at least).

		% ex. GP of Nanjing 2020 K

\section{DFS Algorithms}

	% \kactlimport{DFS/SCC (12.1).h}
	\kactlimport{DFS/EulerPath (12.2).h}
	\kactlimport{DFS/SCCT.h}
	\kactlimport{DFS/TwoSAT (12.1).h}
	\kactlimport{DFS/BCC (12.4).h}
	\kactlimport{DFS/MaximalCliques.h}

\section{Flows}

	\textbf{Konig's Theorem:} In a bipartite graph, max matching = min vertex cover.

	\textbf{Dilworth's Theorem:} For any partially ordered set, the sizes of the max antichain and of the min chain decomposition are equal. Equivalent to Konig's theorem on the bipartite graph $(U,V,E)$ where $U=V=S$ and $(u,v)$ is an edge when $u<v$. Those vertices outside the min vertex cover in both $U$ and $V$ form a max antichain.

	% Wikipedia, https://codeforces.com/gym/102428/problem/A, https://maps20.kattis.com/problems/maps20.thewrathofkahn

	\kactlimport{Flows (12.3)/Dinic.h}
	\kactlimport{Flows (12.3)/GomoryHu.h}
	\kactlimport{Flows (12.3)/MCMF.h}

	% \kactlimport{Flows (12.3)/GlobalMinCut.h}

\section{Matching}

	% \kactlimport{Matching/DFSmatch.h}
	\kactlimport{Matching/Hungarian.h}
	\kactlimport{Matching/UnweightedMatch.h}
	\kactlimport{Matching/WeightedMatch.h}
	\kactlimport{Matching/MaxMatchLexMin.h}
	\kactlimport{Matching/MaxMatchFast.h}
	% \kactlimport{Matching/MaxMatchHeuristic.h}
	% \kactlimport{Matching/UnweightedMatch2.h}

\section{Advanced}

	% \kactlimport{Advanced/MaxClique.h}
	\kactlimport{Advanced/ChordalGraphRecognition.h}
	\kactlimport{Advanced/DominatorTree.h}
	\kactlimport{Advanced/EdgeColor.h}
	\kactlimport{Advanced/DirectedMST.h}
	\kactlimport{Advanced/LCT.h}
	\kactlimport{Advanced/TopTree.h}


\documentclass[11pt]{scrartcl} % Font size
\input{../structure.tex} % Include the file specifying the document structure and custom commands

%----------------------------------------------------------------------------------------
%	TITLE SECTION
%----------------------------------------------------------------------------------------

\title{
	\normalfont\normalsize
	\textsc{Harvard Privacy Tools Project}\\ % Your university, school and/or department name(s)
	\vspace{25pt} % Whitespace
	\rule{\linewidth}{0.5pt}\\ % Thin top horizontal rule
	\vspace{20pt} % Whitespace
	{\huge Mean Sensitivity Proofs}\\ % The assignment title
	\vspace{12pt} % Whitespace
	\rule{\linewidth}{2pt}\\ % Thick bottom horizontal rule
	\vspace{12pt} % Whitespace
}

% \author{\LARGE} % Your name

\date{\normalsize\today} % Today's date (\today) or a custom date

\begin{document}

\maketitle

\begin{definition}
The sample mean of database $X$ of size $n$ is defined as
$$f(X) = \frac{1}{n} \sum_{i=1}^n x_i.$$
\end{definition}
These are restricted-sensitivity proofs that only apply when N is known.
The library makes use of the Resize component to guarantee this static property.
If N is unknown, there is an argument on the DPMean component to estimate the mean by postprocessing plug-in estimates for the count and sum.

\section{Neighboring Definition: Change One}

% l1 sensitivity
\subsection{$\ell_1$-sensitivity}
\begin{theorem}
Say the space of datapoints $\mathcal{X}$ is bounded above by $M$ and bounded below by $m$. Then $f(\cdot)$ has $\ell_1$-sensitivity in the change-one model bounded above by
$$ \frac{M-m}{n}.$$
\end{theorem}

\begin{proof}
Say $X$ and $X'$ are neighboring databases which differ at data-point $x_j$, and let $\Delta{f}$ indicate the $\ell_1$-sensitivity of $f(\cdot)$. Then
\begin{align*}
\Delta{f} &= \max_{X,X'} \left\vert f(X) - f(X)' \right\vert \\
	&=  \max_{X,X'} \frac{1}{n} \left\vert \left(\sum_{\{ i \in [n] \vert i \ne j\}} x_i\right) + x_j  - \left(\sum_{\{ i \in [n] \vert i \ne j\}} x_i'\right) + x_j'  \right\vert \\
	&= \max_{X,X'} \frac{1}{n} \left\vert x_j - x_j' \right\vert \\
	&\le \frac{M-m}{n}.
\end{align*}
\end{proof}

% l2 sensitivity
\subsection{$\ell_2$-sensitivity}
\begin{theorem}
	Say the space of datapoints $\mathcal{X}$ is bounded above by $M$ and bounded below by $m$.
	Then $f(\cdot)$ has $\ell_2$-sensitivity in the change-one model bounded above by
	 $$ \frac{M-m}{n}. $$
\end{theorem}

\begin{proof}
This follows the same logic as the above proof.
\end{proof}

\section{Neighboring Definition: Add/Drop One}
\subsection{$\ell_1$-sensitivity}

\begin{theorem}
Say the space of datapoints $\mathcal{X}$ is bounded above by $M$ and bounded below by $m$.
Then $f(\cdot)$ has $\ell_1$-sensitivity in the add/drop-one model bounded above by
$$ \frac{M-m}{n}. $$
\end{theorem}

\begin{proof}
For notational ease, let $n$ always refer to the size of database $x$. We must consider both adding and removing an element from $x$. First, consider adding a point:\\

Let $X' = X \cup \{x\}$. Without loss of generality, assume the point added is the $(n+1)^{\text{th}}$ element of database $X'$. Note that
\begin{align*}
\left \vert f(X) - f(X)' \right\vert &= \left\vert \frac{1}{n} \sum_{i=1}^n x_i - \frac{1}{n+1} \sum_{i=1}^{n+1} x_i \right\vert \\
	&= \left\vert \left(\frac{1}{n} - \frac{1}{n+1}\right) \sum_{i=1}^n x_i - \frac{x}{n+1}\right\vert \\
	&= \frac{1}{n+1} \left\vert \frac{1}{n} \sum_{i=1}^n x_i - x \right\vert \\
	&\le \frac{ \left\vert M - m \right\vert}{n+1}.
\end{align*}

Second, consider removing a point: \\
Let $X' = X\textbackslash\{x\}$. Without loss of generality assume that the point subtracted is the $n^{\text{th}}$ element of database $X$.
\begin{align*}
\left \vert f(X) - f(X') \right\vert &= \left\vert \frac{1}{n-1} \sum_{i=1}^{n-1} x_i - \frac{1}{n} \sum_{i=1}^n x_i \right\vert \\
	&= \left\vert \left(\frac{1}{n-1} - \frac{1}{n}\right) \sum_{i=1}^{n-1} x_i - \frac{x}{n}\right\vert \\
	&= \frac{1}{n} \left\vert \frac{1}{n-1} \sum_{i=1}^{n-1} x_i  - x \right\vert \\
	&\le \frac{\left\vert M-m\right\vert}{n}.
\end{align*}

Then, since $\forall n > 0,$

$$ \frac{1}{n+1} < \frac{1}{n},$$

the sensitivity of the mean in general is bound from above by

$$ \frac{M-m}{n}.$$
\end{proof}

% l2 sensitivity
\subsection{$\ell_2$-sensitivity}

\begin{theorem}
Say the space of datapoints $\mathcal{X}$ is bounded above by $M$ and bounded below by $m$. Then $f$ has $\ell_2$-sensitivity in the add/drop-one model bounded above by
	$$ \frac{M-m}{n}. $$
\end{theorem}

\begin{proof}
This follows the same logic as the above proof.
%	For notational ease, let $n$ always refer to the size of database $X$. We must consider both adding and removing an element from $X$. First, consider adding a point:
%
%	Let $X' = X \cup x$. Without loss of generality assume the point added is the $(n+1)^\text{th}$ element of database X'. Then,
%	\begin{align*}
%		\Delta f &= \max_{X,X'} \sqrt{(f(X)- f(X)')^2} \\
%					   &= \max_{X,X'} \left( \frac{1}{n}\sum_{i=1}^{n}x_i - \frac{1}{n+1}\sum_{i=1}^{n+1}x'_i \right)\\
%					   &= \max_{X,X'} \left( \left(\frac{1}{n}\sum_{i=1}^{n}x_i\right) - \left(\frac{1}{n+1}\sum_{i=1}^{n}x'_i\right) - \frac{x}{n+1} \right)\\
%					   &= \max_{X,X'} \left( \frac{ \left(\sum_{i=1}^{n}x_i\right) - nx }{n(n+1)} \right)\\
%					   &= \frac{nM - nm}{n(n+1)}\\
%					   &= \frac{M - m}{n+1}.
%	\end{align*}
%
%Second, consider removing an element:\\
%Let $X' = X \setminus \{ x \}$. Without loss of generality assume that the point subtracted is the $n^\text{th}$ element of database $X$. Then,
%	\begin{align*}
%		\Delta f &= \max_{X,X'} (f(X)- f(X)')^2 \\
%					   &= \max_{X,X'} \left( \frac{1}{n}\sum_{i=1}^{n}x_i - \frac{1}{n-1}\sum_{i=1}^{n-1}x'_i \right)\\
%					   &= \max_{X,X'} \left( \left( \frac{1}{n}\sum_{i=1}^{n-1}x_i \right) + \frac{x}{n} - \left( \frac{1}{n-1}\sum_{i=1}^{n-1}x'_i \right) \right) \\
%					   &= \max_{X,X'} \left( \frac{(n-1)x - \sum_{i=1}^{n-1}x_i }{n(n-1)} \right) \\
%					   &= \frac{(n-1)M - (n-1)m}{n(n-1)} \\
%					   &= \frac{M-m}{n}
%	\end{align*}
%
%Then, since $\forall n > 0,$
%
%$$ \frac{1}{n+1} < \frac{1}{n},$$
%
%the sensitivity of the mean in general is bound from above by
%
%$$ \frac{M-m}{n}.$$
\end{proof}

% \bibliographystyle{alpha}
% \bibliography{mean}

\end{document}