\BoSSSopen{tutorial9-SIP/sip}
\graphicspath{{tutorial9-SIP/sip.texbatch/}}

\BoSSScmd{
/// \section*{What's new}
/// \begin{itemize}
/// \item Symmetric Interior Penalty method (SIP)
/// \item investigating matrix properties
/// \end{itemize}
/// \section*{Prerequisites}
/// \begin{itemize}
/// \item basics SIP method
/// \item spatial operator, chapter \ref{SpatialOperator}
/// \item implementing numerical fluxes and convergence study, chapter \ref{NumFlux}
/// \end{itemize}
///
///%_______________________________________________________
/// \section{Problem statement}
/// We consider the 2D Poisson problem:
/// \begin{equation*}
/// \Delta u = f(x,y)
/// \end{equation*}
/// with $f(x,y)\neq 0$ is an arbitrary function of $x$ and/or $y$ or constant.
/// Within this exercise, we are going to investigate the Symmetric Interior Penalty discretization method (SIP) for the Laplace operator:
/// \begin{equation*}
/// a_{\text{sip}}(u,v)
/// = \int_{\domain} \underbrace{\nabla u \cdot \nabla v}_{\text{Volume\ term}}\dV
///   - \oint_{\Gamma \setminus \Gamma_{N }} \underbrace{
///         \mean {\nabla u} \cdot n_{\Gamma}\jump{v}
///      }_{\text{consistency\ term}} + \underbrace{
///         \mean{\nabla v} \cdot \vec{n}_{\Gamma} \jump{u}
///      }_{\text{symmetry\ term}} \dA
///   + \oint_{\Gamma \setminus \Gamma_{N}} \underbrace{
///        \eta \jump{u}\jump{v}
///     }_{\text{penalty\ term}} \dA
/// \end{equation*}
/// The use of these fluxes including a penalty term stabilizes the DG-discretization for the Laplace operator.
///
///%____________________________________________
/// \section{Solution within the \BoSSS{} framework}
/// First, we initialize the new worksheet:
 }
\BoSSSexeSilent
\BoSSScmd{
restart;
 }
\BoSSSexeSilent
\BoSSScmd{
/// We need the following packages:
using ilPSP.LinSolvers;\newline
using ilPSP.Connectors.Matlab;
 }
\BoSSSexe
\BoSSScmdSilent{
/// BoSSScmdSilent BoSSSexeSilent
using NUnit.Framework;
 }
\BoSSSexeSilent
\BoSSScmd{
/// \subsection{Implementation of the SIP fluxes}
/// We are going to implement the SIP-form
/// \begin{equation*}
/// a_{\text{sip}}(u,v)
/// = \int_{\domain} \underbrace{\nabla u \cdot \nabla v}_{\text{volume\ term}}\dV
///   - \oint_{\Gamma \setminus \Gamma_{N }} \underbrace{
///         \mean {\nabla u} \cdot n_{\Gamma}\jump{v}
///      }_{\text{consistency\ term}} + \underbrace{
///         \mean{\nabla v} \cdot \vec{n}_{\Gamma} \jump{u}
///      }_{\text{symmetry\ term}} \dA
///   + \oint_{\Gamma \setminus \Gamma_{N}} \underbrace{
///        \eta \jump{u}\jump{v}
///     }_{\text{penalty\ term}} \dA
/// \end{equation*}
/// First, we need a class in which the integrands are defined.
/// This also includes some technical aspects like the \code{TermActivationFlags}.
public class SipLaplace :\newline
\btab \btab BoSSS.Foundation.IEdgeForm,   // edge integrals\newline
\btab \btab BoSSS.Foundation.IVolumeForm  // volume integrals\newline
\{\newline
    /// We do not use parameters (e.g. variable viscosity, ...)
    /// at this point: so this can be null
\btab public IList<string> ParameterOrdering \{ \newline
\btab \btab get \{ return new string[0]; \} \newline
\btab \} \newline
    /// but we have one argument variable, $u$ (our trial function)
\btab public IList<String> ArgumentOrdering \{ \newline
\btab \btab get \{ return new string[] \{ "u" \}; \} \newline
\btab \}\newline
    /// The \code{TermActivationFlags} tell \BoSSS\ which kind of terms,
    /// i.e. products of $u$, $v$, $\nabla u$, and $\nabla v$
    /// the \code{VolumeForm(...)} actually contains.
    /// This additional information helps to improve the performance.
\btab public TermActivationFlags VolTerms \{\newline
\btab \btab get \{\newline
\btab \btab \btab return TermActivationFlags.GradUxGradV;\newline
\btab \btab \}\newline
\btab \}\newline
    /// activation flags for the 'InnerEdgeForm(...)'
\btab public TermActivationFlags InnerEdgeTerms \{\newline
\btab \btab get \{\newline
\btab \btab \btab return (TermActivationFlags.AllOn);\newline
\btab \btab \btab // if we do not care about performance, we can activate all terms.\newline
\btab \btab \}\newline
\btab \}\newline
\btab public TermActivationFlags BoundaryEdgeTerms \{\newline
\btab    get \{\newline
\btab \btab    return TermActivationFlags.AllOn;\newline
\btab \btab \}\newline
\btab \}\newline
    /// For the computation of the penalty factor $\eta$,
    /// we require
    /// some length scale for each cell and
    /// the polynomial degree of the DG approximation.
\btab public MultidimensionalArray cj;\newline
\btab public int PolynomialDegree;\newline
    /// The safety factor for the penalty factor should be in the order of 1.
    /// A very large penalty factor increases the condition number of the
    /// system, but without affecting stability.
    /// A very small penalty factor yields to an unstable discretization.
\btab public double PenaltySafety = 2.2; \newline
    /// The actual computation of the penalty factor, which should be
    /// used in the \code{InnerEdgeForm} and \code{BoundaryEdgeForm} functions.
    /// Hint: for the parameters \code{jCellIn}, \code{jCellOut} and \code{g},
    /// take a look at
    /// \code{CommonParams} and \code{CommonParamsBnd}.
\btab double PenaltyFactor(int jCellIn, int jCellOut) \{\newline
\btab \btab double cj\_in        = cj[jCellIn];\newline
\btab \btab double penalty\_base = PenaltySafety*PolynomialDegree*PolynomialDegree;\newline
\btab \btab double eta          = penalty\_base * cj\_in;\newline
\btab \btab if(jCellOut >= 0) \{\newline
\btab \btab \btab double cj\_out = cj[jCellOut];\newline
\btab \btab \btab eta           = Math.Max(eta, penalty\_base * cj\_out);\newline
\btab \btab \}\newline
\btab \btab return eta;\newline
\btab \}\newline
    /// The following functions cover the actual math.
    /// For any discretization of the Laplace operator, we have to specify:
    /// \begin{itemize}
    /// \item a volume integrand,
    /// \item an edge integrand for inner edges, i.e. on $\Gamma_i$,
    /// \item an edge integrand for boundary edges, i.e. on $\partial \Omega$.
    /// \end{itemize}
    /// The integrand for the volume integral:
\btab public double VolumeForm(ref CommonParamsVol cpv, \newline
\btab \btab    double[] U, double[,] GradU, // the trial-function u \newline
\btab \btab    //            (i.e. the function we search for) and its gradient\newline
\btab \btab    double V, double[] GradV     // the test function; \newline
\btab \btab    ) \{\newline
 \newline
\btab \btab double acc = 0;\newline
\btab \btab for(int d = 0; d < cpv.D; d++)\newline
\btab \btab \btab acc += GradU[0, d] * GradV[d];\newline
\btab \btab return acc;\newline
\btab \}\newline
    /// The integrand for the integral on the inner edges,
    /// \[
    ///   -( \mean{ \nabla u } \jump{ v }) \cdot \vec{n}_{\Gamma}
    ///   -( \mean{ \nabla v } \jump{ u }) \cdot \vec{n}_{\Gamma}
    ///   + \eta \jump{ u }  \jump{v} :
    /// \]
\btab public double InnerEdgeForm(ref CommonParams inp, \newline
\btab \btab double[] U\_IN, double[] U\_OT, double[,] GradU\_IN, double[,] GradU\_OT, \newline
\btab \btab double V\_IN, double V\_OT, double[] GradV\_IN, double[] GradV\_OT) \{\newline
 \newline
\btab \btab double eta = PenaltyFactor(inp.jCellIn, inp.jCellOut);\newline
 \newline
\btab \btab double Acc = 0.0;\newline
\btab \btab for(int d = 0; d < inp.D; d++) \{ // loop over vector components \newline
\btab \btab \btab // consistency term: -(\{\{ \textbackslash /u \}\} [[ v ]])*Normale\newline
\btab \btab \btab // index d: spatial direction\newline
\btab \btab \btab Acc -= 0.5 * (GradU\_IN[0, d] + GradU\_OT[0, d])*(V\_IN - V\_OT)\newline
\btab \btab \btab \btab \btab    * inp.Normale[d];\newline
 \newline
\btab \btab \btab // symmetry term: -(\{\{ \textbackslash /v \}\} [[ u ]])*Normale\newline
\btab \btab \btab Acc -= 0.5 * (GradV\_IN[d] + GradV\_OT[d])*(U\_IN[0] - U\_OT[0])\newline
\btab \btab \btab \btab \btab    * inp.Normale[d];;\newline
\btab \btab \}\newline
 \newline
\btab \btab // penalty term: eta*[[u]]*[[v]]\newline
\btab \btab Acc += eta*(U\_IN[0] - U\_OT[0])*(V\_IN - V\_OT);\newline
\btab \btab return Acc;\newline
\btab \} \newline
    /// The integrand on boundary edges, i.e. on $\partial \Omega$, is
    /// \[
    ///   -( \mean{ \nabla u } \jump{ v }) \cdot \vec{n}_{\Gamma}
    ///   -( \mean{ \nabla v } \jump{ u }) \cdot \vec{n}_{\Gamma}
    ///   +  \eta \jump{ u }  \jump{v} .
    /// \]
    /// For the boundary we have to consider the special definition for
    /// the mean-value operator $\mean{-}$ and the jump operator
    /// $\jump{-}$ on the boundary.
\btab public double BoundaryEdgeForm(ref CommonParamsBnd inp, \newline
\btab \btab double[] U\_IN, double[,] GradU\_IN, double V\_IN, double[] GradV\_IN) \{\newline
 \newline
\btab \btab double eta = PenaltyFactor(inp.jCellIn, -1);\newline
\btab \btab double Acc = 0.0;\newline
\btab \btab for(int d = 0; d < inp.D; d++) \{ // loop over vector components \newline
\btab \btab \btab // consistency term: -(\{\{ \textbackslash /u \}\} [[ v ]])*Normale\newline
\btab \btab \btab // index d: spatial direction\newline
\btab \btab \btab Acc -= (GradU\_IN[0, d])*(V\_IN) * inp.Normale[d];\newline
 \newline
\btab \btab \btab // symmetry term: -(\{\{ \textbackslash /v \}\} [[ u ]])*Normale\newline
\btab \btab \btab Acc -= (GradV\_IN[d])*(U\_IN[0]) * inp.Normale[d];;\newline
\btab \btab \}\newline
 \newline
\btab \btab // penalty term: eta*[[u]]*[[v]]\newline
\btab \btab Acc += eta*(U\_IN[0])*(V\_IN);\newline
 \newline
 \newline
\btab \btab return Acc;\newline
\btab \}\newline
\}
 }
\BoSSSexe
\BoSSScmd{
/// \subsection{Evaluation of the poisson operator in 1D}
/// We consider the following problem:
/// \begin{equation*}
/// \Delta u = 2,\quad -1<x<1,\quad u(-1)=u(1)=0.
/// \end{equation*}
/// The solution is $u_{ex}(x) = 1 - x^2$. Since this is quadratic, we can represent it \emph{exactly} in a DG space of order 2.
/// As usual, we have to set up a grid and a basis:
var grd1D                     = Grid1D.LineGrid(GenericBlas.Linspace(-1,1,10));\newline
var gdata1D                   = new GridData(grd1D);\newline
var DGBasisOn1D               = new Basis(gdata1D,2);\newline
/// and a right-hand-side:
var RHS                       = new SinglePhaseField(DGBasisOn1D, "RHS");\newline
RHS.ProjectField((double x) => 2);\newline
/// We have to ensure to set the \code{PolynomialDegree} in the \emph{SipLaplace}-object.
var i\_SipLaplace              = new SipLaplace();\newline
i\_SipLaplace.PolynomialDegree = DGBasisOn1D.Degree;\newline
i\_SipLaplace.cj               = gdata1D.Cells.cj;\newline
var Operator\_SipLaplace       = i\_SipLaplace.Operator();\newline
/// We now want to calculate the residual after inserting the exact solution as well as a wrong solution.
/// The implementation of the exact solution:
var u\_ex         = new SinglePhaseField(DGBasisOn1D, "$u\_\{ex\}$");\newline
u\_ex.ProjectField((double x) => 1.0 - x*x);\newline
/// The implementation of a spurious, i.e. a wrong solution; we take the exact solution and add random values in each cell:
var u\_wrong      = new SinglePhaseField(DGBasisOn1D, "$u\_\{wrong\}$");\newline
u\_wrong.ProjectField((double x) => 1.0 - x*x);\newline
Random R         = new Random();\newline
for(int j = 0; j < gdata1D.Cells.NoOfLocalUpdatedCells; j++)\{\newline
\btab double ujMean = u\_wrong.GetMeanValue(j);\newline
\btab ujMean += R.NextDouble();\newline
\btab u\_wrong.SetMeanValue(j, ujMean);\newline
\btab \}\newline
/// Evaluating the Laplace operator using the different solutions:
var Residual     = new SinglePhaseField(DGBasisOn1D,"Resi1");\newline
var ResidualNorm = new List<double>();\newline
foreach(var u in new DGField[] \{u\_ex, u\_wrong\}) \{\newline
\btab Residual.Clear();\newline
\btab Operator\_SipLaplace.Evaluate(u, Residual);  // evaluate\newline
\btab Residual.Acc(-1.0, RHS);    \newline
\btab double ResiNorm = Residual.L2Norm();\newline
\btab ResidualNorm.Add(ResiNorm);\newline
\btab Console.WriteLine("Residual for " + u.Identification + " = " + ResiNorm);  \newline
\}
 }
\BoSSSexe
\BoSSScmdSilent{
/// tests BoSSScmdSilent
Assert.LessOrEqual(ResidualNorm[0], 1e-10);\newline
Assert.GreaterOrEqual(ResidualNorm[1], 1e-1);
 }
\BoSSSexe
\BoSSScmd{
/// \subsection{The matrix of the Poisson Operator}
/// If we do not know the exact solution, we have to solve a linear system.
/// Therefore, we not only need to evaluate the operator,
/// but we need its matrix.
/// The \emph{Mapping} controls which degree-of-freedom of the DG approximation
/// is mapped to which row, resp. column of the matrix.
var Mapping           = new UnsetteledCoordinateMapping(DGBasisOn1D);\newline
var Matrix\_SipLaplace = Operator\_SipLaplace.ComputeMatrix(Mapping,null,Mapping);
 }
\BoSSSexe
\BoSSScmd{
Matrix\_SipLaplace.NoOfCols;
 }
\BoSSSexe
\BoSSScmd{
Matrix\_SipLaplace.NoOfRows;
 }
\BoSSSexe
\BoSSScmd{
/// We see that the matrix has 27 rows and columns.
 }
\BoSSSexe
\BoSSScmd{
/// \paragraph{Matrix rank and determinant of the matrix
///  \code{Matrix\_SipLaplace}:}
/// Use the functions \emph{rank} and \emph{det} to analyze the matrix (warning: this can get costly
/// for larger matrices!).\\
///Interpret the results:
/// \begin{itemize}
/// \item What does it mean, when a matrix has full rank?
/// \item How many solutions can a linear system have?
/// \end{itemize}
double rank = Matrix\_SipLaplace.rank(); \newline
Console.WriteLine("Matrix rank = " + rank);\newline
 \newline
double det = Matrix\_SipLaplace.det();   \newline
Console.WriteLine("Determinante = " + det);\newline
/// So the matrix of the SIP discretization has a unique solution.
 }
\BoSSSexe
\BoSSScmdSilent{
/// tests BoSSScmdSilent
Assert.AreEqual(rank, Matrix\_SipLaplace.NoOfCols);\newline
Assert.Greater(det, 1.0);
 }
\BoSSSexe
\BoSSScmd{
 %
 }
\BoSSSexe
\BoSSScmd{
/// \section{Advanced topics}
 }
\BoSSSexe
\BoSSScmd{
/// %========================================================
/// %========================================================
/// \subsection{The penalty parameter of the SIP and stability in 2D}
/// %========================================================
/// %========================================================
 }
\BoSSSexe
\BoSSScmd{
/// We define a two-dimensional grid:
var grd2D       = Grid2D.Cartesian2DGrid(GenericBlas.Linspace(-1,1,21), \newline
\btab \btab \btab \btab \btab \btab \btab \btab \btab \btab  GenericBlas.Linspace(-1,1,16));\newline
var gdata2D     = new GridData(grd2D);\newline
var DGBasisOn2D = new Basis(gdata2D, 5);\newline
var Mapping2D   = new UnsetteledCoordinateMapping(DGBasisOn2D);
 }
\BoSSSexe
\BoSSScmd{
/// We are going to choose the \code{PenaltySafety} for the \code{SipLaplace}
/// from the following list
double[] SFs = new double[] \newline
\btab   \{0.001, 0.002, 0.01, 0.02, 0.1, 0.2, 1, 2, 10, 20, 100\};\newline
/// and compute the condition number as well as the determinate.
 }
\BoSSSexe
\BoSSScmd{
/// We consider the example
/// \[
///     -\Delta u = \pi^2 0.5 \cos(x/2) \cos(y/2)
///       \text{ with }
///       (x,y) \in (-1,1)^2
/// \]
/// and $u = 0$ on the boundary.
/// The exact solution is $u_{Ex}(x,y) = \cos(x/2) \cos(y/2)$.
Func<double[], double> exSol = \newline
\btab \btab (X => Math.Cos(X[0]*Math.PI*0.5)*Math.Cos(X[1]*Math.PI*0.5));\newline
Func<double[], double> exRhs = \newline
\btab \btab (X => (Math.PI*Math.PI*0.5*Math.Cos(X[0]*Math.PI*0.5)\newline
\btab \btab \btab \btab \btab   *Math.Cos(X[1]*Math.PI*0.5))); // == - /\textbackslash  exSol\newline
SinglePhaseField RHS = new SinglePhaseField(DGBasisOn2D, "RHS");\newline
RHS.ProjectField(exRhs);\newline
double[] RHSvec = RHS.CoordinateVector.ToArray();
 }
\BoSSSexe
\BoSSScmd{
/// We check our discretization once more in 2D; the residual should be low,
/// but not exactly (resp. up to $10^{-12}$) since the solution is not
/// polynomial and cannot be fulfilled exactly.
SinglePhaseField u = new SinglePhaseField(DGBasisOn2D,"u");\newline
u.ProjectField(exSol);\newline
i\_SipLaplace.PolynomialDegree = DGBasisOn2D.Degree;\newline
i\_SipLaplace.cj               = gdata2D.Cells.cj;\newline
var Matrix\_SIP\_sf     = Operator\_SipLaplace.ComputeMatrix(Mapping2D,\newline
\btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab   null,\newline
\btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab \btab   Mapping2D);\newline
SinglePhaseField Residual = new SinglePhaseField(DGBasisOn2D,"Residual");\newline
Residual.Acc(1.0, RHS);\newline
Matrix\_SIP\_sf.SpMV(-1.0, u.CoordinateVector, 1.0, Residual.CoordinateVector);\newline
Console.WriteLine("Residual L2 norm: " + Residual.L2Norm());
 }
\BoSSSexe
\BoSSScmd{
/// We also check that the matrix is symmetric:
var checkMatrix = Matrix\_SIP\_sf - Matrix\_SIP\_sf.Transpose();\newline
checkMatrix.InfNorm();
 }
\BoSSSexe
\BoSSScmdSilent{
/// tests BoSSScmdSilent
Assert.LessOrEqual(checkMatrix.InfNorm(), 1e-8);
 }
\BoSSSexe
\BoSSScmd{
/// \paragraph{Matrix properties for different penalty factors.}
/// Now, we assemble the matrix of the SIP for different
/// \code{PenaltySafety}-factors. We also try to solve the linear system
/// using an iterative method. As Matlab is called multiple times during this
/// command, it can take some minutes until it is done.
int cnt     = 0;\newline
var Results = new List<Tuple<double,double,int,double,bool>>();\newline
foreach(double sf in SFs) \{\newline
\btab cnt++;\newline
\btab i\_SipLaplace.PenaltySafety    = sf;\newline
\btab i\_SipLaplace.PolynomialDegree = DGBasisOn2D.Degree;\newline
\btab var Matrix\_SIP\_sf             = Operator\_SipLaplace.ComputeMatrix(\newline
\btab \btab \btab \btab \btab \btab \btab \btab \btab Mapping2D,null,Mapping2D);\newline
\btab double condNo1                = Matrix\_SIP\_sf.condest();  \newline
\btab bool definite                 = Matrix\_SIP\_sf.IsDefinite();\newline
 \newline
    /// We solve the system
    /// \[
    ///    \text{\tt Matrix\_SIP\_sf} \cdot u = \text{\tt RHS}
    /// \]
    /// using a an iterative solver, the so-called
    /// conjugate gradient (CG) method.
    /// CG requires a positive definite matrix.
    /// The function \code{Solve\_CG} returns the number of iterations.
\btab SinglePhaseField u = new SinglePhaseField(DGBasisOn2D,"u");\newline
\btab u.InitRandom();\newline
\btab int NoOfIter = Matrix\_SIP\_sf.Solve\_CG(u.CoordinateVector, RHSvec);\newline
 \newline
\btab SinglePhaseField Error = new SinglePhaseField(DGBasisOn2D,"Error");\newline
\btab Error.ProjectField(exSol);\newline
\btab Error.Acc(-1.0, u);\newline
 \newline
\btab double L2err = u.L2Error(exSol);\newline
 \newline
\btab Console.WriteLine(sf + "\textbackslash t" + condNo1.ToString("0.#E-00") \newline
\btab \btab \btab \btab \btab \btab  + "\textbackslash t" + NoOfIter \newline
\btab \btab \btab \btab \btab \btab  + "\textbackslash t" + L2err.ToString("0.#E-00") \newline
\btab \btab \btab \btab \btab \btab  + "\textbackslash t" + definite);\newline
\btab Results.Add(new Tuple<double,double,int,double,bool>(sf, condNo1, NoOfIter,\newline
\btab \btab \btab \btab \btab \btab \btab \btab  L2err, definite));\newline
\}
 }
\BoSSSexe
\BoSSScmdSilent{
/// tests BoSSScmdSilent
foreach(var r in Results) \{\newline
\btab if(r.Item1 >= 1 && r.Item1 <= 20) \{\newline
\btab \btab Assert.LessOrEqual(r.Item2, 1e7); // cond No.\newline
\btab \btab Assert.LessOrEqual(r.Item3, 6000); // iter\newline
\btab \btab Assert.LessOrEqual(r.Item4, 1e-4); // L2 err\newline
\btab \btab Assert.IsTrue(r.Item5); // definite   \newline
\btab \}\newline
\btab if(r.Item1 <= 0.1) \{\newline
\btab \btab Assert.IsFalse(r.Item5); // indefinite   \newline
\btab \}\newline
\}
 }
\BoSSSexe
\BoSSScmd{
/// \paragraph{Plotting:}
/// Plot the number of conjugate gradient iterations versus the
/// \code{PenaltySafety}.
/// A logarithmic scale is used for the horizontal axis.
var format = new PlotFormat(lineColor: LineColors.Blue, \newline
\btab \btab \btab \btab \btab \btab \btab pointSize: 2, \newline
\btab \btab \btab \btab \btab \btab \btab dashType: DashTypes.DotDashed, \newline
\btab \btab \btab \btab \btab \btab \btab Style: Styles.LinesPoints, \newline
\btab \btab \btab \btab \btab \btab \btab pointType:PointTypes.OpenCircle);\newline
Gnuplot gp = new Gnuplot(baseLineFormat:format);\newline
gp.PlotLogXY(Results.Select(r => r.Item1), \newline
\btab \btab \btab  Results.Select(r => ((double)(r.Item3))));\newline
gp.PlotNow();
 }
\BoSSSexe
\BoSSScmd{
/// \paragraph{Convergence study, indefinite vs. definite.}
/// We are going to solve the SIP-system for different grid resolutions,
/// comparing an insufficient penalty to a penalty which is large enough.
double[] Resolution = new double[] \{ 8, 16, 32, 64, 128, 256 \};\newline
List<double> L2Error\_indef  = new List<double>();\newline
List<double> L2Error\_posdef = new List<double>();\newline
foreach(int Res in Resolution) \{\newline
\btab var grd2D = Grid2D.Cartesian2DGrid(GenericBlas.Linspace(-1,1,(int)Res + 1), \newline
\btab \btab \btab \btab \btab \btab \btab \btab \btab    GenericBlas.Linspace(-1,1,(int)Res + 1));\newline
\btab var gdata2D = new GridData(grd2D);\newline
\btab var DGBasisOn2D = new Basis(gdata2D, 2);\newline
\btab var Mapping2D  = new UnsetteledCoordinateMapping(DGBasisOn2D);\newline
 \newline
\btab SinglePhaseField RHS = new SinglePhaseField(DGBasisOn2D, "RHS");\newline
\btab RHS.ProjectField(exRhs);\newline
\btab SinglePhaseField uEx = new SinglePhaseField(\newline
\btab \btab    new Basis(gdata2D, DGBasisOn2D.Degree*2),\newline
\btab \btab    "Error");\newline
\btab uEx.ProjectField(exSol);\newline
 \newline
\btab i\_SipLaplace.PolynomialDegree = DGBasisOn2D.Degree;\newline
\btab i\_SipLaplace.cj               = gdata2D.Cells.cj;\newline
 \newline
\btab i\_SipLaplace.PenaltySafety    = 0.01;\newline
\btab var Matrix\_SIP\_indef          = Operator\_SipLaplace.ComputeMatrix(\newline
\btab \btab \btab \btab \btab \btab \btab \btab \btab Mapping2D,null,Mapping2D);\newline
 \newline
\btab SinglePhaseField u\_indef = new SinglePhaseField(DGBasisOn2D,"u");\newline
\btab Matrix\_SIP\_indef.Solve\_Direct(u\_indef.CoordinateVector, \newline
\btab \btab \btab \btab \btab \btab \btab \btab   RHS.CoordinateVector);\newline
\btab var Error\_indef = uEx.CloneAs();\newline
\btab Error\_indef.AccLaidBack(-1.0, u\_indef);\newline
\btab L2Error\_indef.Add(Error\_indef.L2Norm());\newline
 \newline
    /// In order to have a positive definite system, we are
    /// using $\text{\tt PenaltySafety} = 2$!
\btab i\_SipLaplace.PenaltySafety = 2.0;\newline
\btab var Matrix\_SIP\_posdef         = Operator\_SipLaplace.ComputeMatrix(\newline
\btab \btab \btab \btab \btab \btab \btab \btab \btab Mapping2D,null,Mapping2D);\newline
 \newline
\btab SinglePhaseField u\_posdef = new SinglePhaseField(DGBasisOn2D,"u");\newline
\btab Matrix\_SIP\_posdef.Solve\_Direct(u\_posdef.CoordinateVector, \newline
\btab \btab \btab \btab \btab \btab \btab \btab    RHS.CoordinateVector);\newline
\btab var Error\_posdef = uEx.CloneAs();\newline
\btab Error\_posdef.AccLaidBack(-1.0, u\_posdef);\newline
\btab L2Error\_posdef.Add(Error\_posdef.L2Norm());\newline
 \newline
\btab Console.WriteLine(L2Error\_indef.Last().ToString("0.#E-00") \newline
\btab \btab \btab \btab \btab   + "\textbackslash t" + L2Error\_posdef.Last().ToString("0.#E-00"));\newline
\}
 }
\BoSSSexe
\BoSSScmd{
/// \paragraph{Convergence plot:}
/// The convergence plot unveils that there is something wrong if the
/// penalty factor is set too low.
/// While the solution of the indefinite system may look right at the first
/// glance, we see that we do not obtain grid convergence for
/// \code{Error\_indef}.
/// The error of the positive definite system, \code{Error\_posdef}, where the
/// penalty is chosen sufficiently large converges with the expected
/// rate.
var format = new PlotFormat(lineColor: LineColors.Blue, \newline
\btab \btab \btab \btab \btab \btab \btab pointSize: 2, \newline
\btab \btab \btab \btab \btab \btab \btab dashType: DashTypes.DotDashed, \newline
\btab \btab \btab \btab \btab \btab \btab Style: Styles.LinesPoints, \newline
\btab \btab \btab \btab \btab \btab \btab pointType:PointTypes.OpenCircle);\newline
Gnuplot gp = new Gnuplot(baseLineFormat:format);\newline
gp.PlotLogXLogY(Resolution, L2Error\_indef);\newline
gp.PlotLogXLogY(Resolution, L2Error\_posdef);\newline
gp.PlotNow();
 }
\BoSSSexe
\BoSSScmd{
/// Finally, we are going to compute the convergence rate of the SIP
/// discretization: we take the logarithm of the resolution and the error:
 }
\BoSSSexe
\BoSSScmd{
var log\_h   = Resolution.Select(h => Math.Log10(h)).ToArray();\newline
var log\_Err = L2Error\_posdef.Select(h => Math.Log10(h)).ToArray();
 }
\BoSSSexe
\BoSSScmd{
var LeastSquaresSys = MultidimensionalArray.Create(log\_h.Length,2);\newline
LeastSquaresSys.SetColumn(0, log\_h.Length.ForLoop(i => 1.0));\newline
LeastSquaresSys.SetColumn(1, log\_h);\newline
double[] dk = new double[2]; // intercept and slope of best-fit line\newline
LeastSquaresSys.LeastSquareSolve(dk, log\_Err);
 }
\BoSSSexe
\BoSSScmd{
dk;
 }
\BoSSSexe
\BoSSScmdSilent{
/// tests BoSSScmdSilent
Assert.LessOrEqual(dk[1], -2.9);
 }
\BoSSSexe
\BoSSScmd{
/// \section{Further reading}
/// \begin{itemize}
/// \item
/// \bibentry{DiPietroErn2011}
/// \item
/// \bibentry{Arnold_1982}
/// \end{itemize}
 }
\BoSSSexe


\section{Asymmetric-Key Encryption (Public-Key Encryption)}\label{s:public-key-encryption}
The major problem that traditional symmetric-key algorithms face is that they require the parties to exchange keys, or more specifically to agree to a secret common private key, prior to communicating.
This needs a secure (physical or digital) communication channel accessible even for a short period of time, in order for the secret key to be exchanged. Such a channel could be a piece of paper delivered by hand or by a trusted courier, or a short in person communication.

An asymmetric or public-key cryptosystem is one where different keys are employed for the operations in the cryptosystem (\textit{e.g.}, encryption and decryption), and where one of the keys can be made public without compromising the secrecy of the other key \cite{Kaliski2011}. That way there is no need for a secure channel or prior agreement.

Usually three algorithms are needed to define a public key cryptosystem. These are a \textit{Key Generation} algorithm which produces the public and private keys (based on a security parameter $\eta$), an \textit{Encryption} and a \textit{Decryption} algorithm.

In the classic model such an encryption scheme involves a \textit{public key} which is used for encryption and a \textit{private key} which is used for decryption.
More formally, given a plaintext $P$, a public key $PubKey$, and a private key $PrivKey$ we can produce a ciphertext $C$ such that:
\begin{equation}
  \label{eq:public-key-encryption}
  \begin{aligned}
    C = Enc(P, PubKey)\\
    P = Dec(C, PrivKey)
  \end{aligned}
\end{equation}

Where $Enc$ and $Dec$ are the \textit{Encryption} and \textit{Decryption} algorithms respectively.

If Alice wants to send a message to Bob, she needs Bob's public key which could be publicly available (\textit{e.g.} on Bob's website).
Alice encrypts her message with Bob's public key and sends the resulted ciphertext to Bob. Bob then needs his private key which is only in his possession in order to decrypt the ciphertext Alice sent and retrieve the original message.
If Bob wishes to reply, he needs Alice's public key etc.
Generally, the public (encryption) key could be shared to any party that wants to communicate with the owner of that public key, while the private (decryption) key should be kept secret and used by the recipient of the ciphertext to recover the original plaintext.

The ability for two users to establish a shared secret over an insecure communication channel, despite having no prior communication or information exchange was first proposed in 1976 by Whitfield Diffie and Martin Hellman.
That method is named Diffie-Hellman (DH) key exchange \cite{diffie1976new} after its authors. The security of the algorithm is based on the difficulty of solving the Discrete Log Problem (DLP). The DLP is stated as follows: Given $g, p$ and $g^k \pmod{p}$, find $k$.

Some of the most widely used public key cryptosystems are the RSA (Rivest -- Shamir -- Adleman) \cite{rivest1978method}, the El Gamal \cite{elgamal1985public} and the Paillier \cite{paillier1999public} Cryptosystems.

\subsection{RSA}\label{s:pk-rsa}

One if the first and most widely adopted public key cryptosystem is RSA . The algorithm's difficulty reduces to the difficulty of factoring the product of two large prime numbers. Its three basic algorithms are described below.

\begin{itemize}
  \item \textit{Key Generation}
  \begin{itemize}
    \item Randomly select two large primes $p$ and $q$.
    \item Calculate modulus $n = p \cdot q$.
    \item Calculate $\phi(n) = (p-1) \cdot (q-1)$.
    \item Randomly select $e : gcd(e,\phi(n)) = 1$.
    \item Calculate reverse $d  = e ^ {-1} \pmod{\phi(n)}$.\\
    $d \cdot e = 1 \pmod{\phi(n)}$.
    \item The public key is $(n, e)$, while the private key is $d$. $p, q$ and $\phi(n)$ must also be kept private.
  \end{itemize}
  \item \textit{Encryption}
  \begin{itemize}
    \item Given a plaintext message $m$, we get a ciphertext $c = m ^ e \pmod{n}$.
  \end{itemize}
  \item \textit{Decryption}
  \begin{itemize}
    \item Given a ciphertext $c$, we get back the plaintext $m$ as follows: $c^d \pmod{n} = m^{ed} \pmod{n} = m$.
  \end{itemize}
\end{itemize}

\subsection{ElGamal}\label{s:pk-elgamal}
The ElGamal encryption system is a public-key cryptosystem based on the Diffie-Hellman key exchange. Its three basic algorithms are described below.

\begin{itemize}
  \item \textit{Key Generation}
  \begin{itemize}
    \item Select two large primes $p$ and $ q : q \mid (p - 1)$.
    \item Select a generator $g$ of group $\mathbb{G}$ which is a large enough order-$q$ subgroup of the multiplicative group $\mathbb{Z}_{p}^{*}$ of integers between $1$ and $p - 1$.
    \item Randomly select $ x \in_{R} \mathbb{Z}_{q}$.
    \item Calculate $y = g^{x} \pmod{p}$.
    \item The public key is $y$, while the private key is $x$.
  \end{itemize}
  \item \textit{Encryption}
  \begin{itemize}
    \item Given a plaintext message $m$, we get a ciphertext $c$ as follows.
    \item Randomly select $r \in_{R} \mathbb{Z}_{q}$.
    \item Calculate $G = g^{r} \pmod{p}$.
    \item Calculate $M = m \cdot y^{r} \pmod{p}$.
    \item Return $c = (G,M)$
  \end{itemize}
  \item \textit{Decryption}
  \begin{itemize}
    \item Given a ciphertext $c = (G,M)$, we get back the plaintext $m$ as follows: \\$m = M/G^{x}\pmod{p}$.
  \end{itemize}
\end{itemize}

\subsection{Paillier}\label{s:pk-paillier}
The Pallier cryptosystem is a public-key cryptosystem that relies its security upon the decisional composite residuosity assumption \cite{paillier1999public}.

\begin{itemize}
  \item \textit{Key Generation}
  \begin{itemize}
    \item Randomly and independently select two large primes $p$ and \\$ q :gcd(p-1, q-1) = 1$ If both primes have the same length this property holds.
    \item Calculate the RSA modulus $n = p \cdot q$.
    \item Calculate $\lambda = lcm(p-1, q-1)$.
    \item Select generator $g \in \mathbb{Z}_{n^{2}}^{*}$ such that the order of $g$ is a non zero multiple of $n$.
    \item Calculate $\mu = (L(g^{\lambda} \pmod{n^{2}}))^{-1} \pmod{n}$, where $L(x) = \frac{x-1}{n}$.
    \item The public key is $ (n,g) $, while the private key is $ (\lambda, \mu) $.
  \end{itemize}
  \item \textit{Encryption}
  \begin{itemize}
    \item Given a plaintext message $m$, we get a ciphertext $c$ as follows.
    \item Encode $m$ into $\mathbb{Z}_{n}$.
    \item Randomly select $ r \in_{R} \mathbb{Z}_{n}^{*}$.
    \item Return $c = g^{m} \cdot r^{n} \pmod{n^{2}}$.
  \end{itemize}
  \item \textit{Decryption}
  \begin{itemize}
    \item Given a ciphertext $c \in \mathbb{Z}_{n^{2}}$, we get back the plaintext $m$ as follows: \\$m = L(c^{\lambda} \pmod{n^{2}}) \cdot \mu \pmod{n}$.
  \end{itemize}
\end{itemize}


% Part: first-order-logic
% Chapter: introduction
% Section: formulas

\documentclass[../../../include/open-logic-section]{subfiles}

\begin{document}

\olfileid{fol}{int}{fml}

\section{\usetoken{P}{formula}}

Here is the approach we will use to rigorously specify !!{sentence}s
of first-order logic and to deal with the issues arising from the use
of !!{variable}s. We first define a \emph{different} set of
expressions: !!{formula}s. Once we've done that, we can consider the
role !!{variable}s play in them---and on the basis of some other
ideas, namely those of ``free'' and ``bound'' !!{variable}s, we can
define what !!a{sentence} is (namely, !!a{formula} without free
!!{variable}s). We do this not just because it makes the definition of
``!!{sentence}'' more manageable, but also because it will be crucial
to the way we define the semantic notion of satisfaction.

Let's define ``!!{formula}'' for a simple first-order language, one
containing only a single !!{predicate}~$\Obj P$ and a single
!!{constant}~$\Obj a$, and only the logical symbols $\lnot$, $\land$,
and~$\lexists$. Our full definitions will be much more general:
we'll allow infinitely many !!{predicate}s and !!{constant}s. In fact,
we will also consider !!{function}s which can be combined with
!!{constant}s and !!{variable}s to form ``terms.'' For now, $\Obj a$
and the variables will be our only terms.  We do need infinitely many
!!{variable}s.  We'll officially use the symbols $\Obj v_0$, $\Obj
v_1$, \dots, as variables.

\begin{defn}
The set of \emph{!!{formula}s}~$\Frm$ is defined as follows:
\begin{enumerate}
\item\ollabel{fmls-atom} $\Atom{\Obj P}{\Obj a}$ and $\Atom{\Obj
  P}{\Obj v_i}$ are !!{formula}s ($i \in \Nat$).

\tagitem{prvNot}{If $!A$ is !!a{formula}, then $\lnot !A$ is
  !!{formula}.}{}

\tagitem{prvAnd}{If $!A$ and $!B$ are !!{formula}s, then $(!A \land
  !B)$ is !!a{formula}.}{}

\tagitem{prvEx}{If $!A$ is !!a{formula} and $x$ is !!a{variable},
  then $\lexists[x][!A]$ is !!a{formula}.}{}

\tagitem{limitClause}{\ollabel{fmls-limit}Nothing else is !!a{formula}.}{}
\end{enumerate}
\end{defn}

\olref{fmls-atom} tell us that $\Atom{\Obj P}{\Obj a}$ and $\Atom{\Obj
P}{\Obj v_i}$ are !!{formula}s, for any $i \in \Nat$. These are
the so-called \emph{atomic} !!{formula}s. They give us something to
start from.  The other clauses give us ways of forming new
!!{formula}s from ones we have already formed. So for instance, we get
that $\lnot \Atom{\Obj P}{\Obj v_2}$ is !!a{formula}, since
$\Atom{\Obj P}{\Obj v_2}$ is already !!a{formula} by
\olref{fmls-atom}, and then we get that $\lexists[\Obj v_2][\lnot
\Atom{\Obj P}{\Obj v_2}]$ is another !!{formula}, and so on.
\olref{fmls-limit} tells us that \emph{only} strings we can form in
this way count as !!{formula}s. In particular, $\lexists[\Obj
v_0][\Atom{\Obj P}{\Obj a}]$ and $\lexists[\Obj v_0][\lexists[\Obj
v_0][\Atom{\Obj P}{\Obj a}]]$ \emph{do} count as !!{formula}s, and
$(\lnot \Atom{\Obj P}{\Obj a})$ does not.

This way of defining !!{formula}s is called an \emph{inductive
definition}, and it allows us to prove things about !!{formula}s using
a version of proof by induction called \emph{structural induction}.
These are discussed in a general way in \olref[mth][ind][idf]{sec} and
\olref[mth][ind][sti]{sec}, which you should review before delving
into the proofs later on. Basically, the idea is that if you want to
give a proof that something is true for all !!{formula}s you show
first that it is true for the atomic !!{formula}s, and then that
\emph{if} it's true for any !!{formula}~$!A$ (and~$!B$), it's
\emph{also} true for $\lnot !A$, $(!A \land !B)$, and
$\lexists[x][!A]$. For instance, this proves that it's true for
$\lexists[\Obj v_2][\lnot \Atom{\Obj P}{\Obj v_2}]$: from the first
part you know that it's true for the atomic !!{formula}~$\Atom{\Obj
P}{\Obj v_2}$. Then you get that it's true for $\lnot \Atom{\Obj
P}{\Obj v_2}$ by the second part, and then again that it's true for
$\lexists[\Obj v_2][\lnot \Atom{\Obj P}{\Obj v_2}]$ itself. Since all
!!{formula}s are inductively generated from atomic !!{formula}s, this
works for any of them.

\end{document}


\documentclass[../PHYS306Notes.tex]{subfiles}

\begin{document}
\subsection{Worksheet - Review of Damped \& Driven Harmonic Oscillators}
\begin{p}
An undamped harmonic oscillator has general solution $x(t) = B_1\cos(\omega t) + B_2\sin(\omega t)$. Show this can be recast as $x(t) = A\cos(\omega t - \delta)$, where $A = \sqrt{A^2 + B^2}$.
\end{p}
\begin{s}
Consider a right-angle triangle with side lengths $B_1$, $B_2$ and hypotenuse $A + \sqrt{B_1^2 + B_2^2}$. Then, let $\cos\delta = \frac{B_1}{A}$ and $\sin\delta = \frac{B_2}{A}$. Looking at the equation for $x(t)$ above, we can multiply it by one in a clever way:
\[x(t) = A\left[\frac{B_1}{A}\cos\omega t + \frac{B_2}{A}\sin\omega t\right] = A\left[\cos\delta\cos\omega t + \sin\delta \sin\omega t\right] = A\cos(\omega t - \delta)\]
Where the last equality follows by a trigonometric identity.
\end{s}

\begin{p}
Show that the kinetic and potential energy of a simple undamped oscillator have the same amplitude but are out of phase, such that the total energy is conserved.
\end{p}
\begin{s}
Using our equation for $x(t)$ above (where $x(t)$ is the displacement from equilibrium), the total energy is given by:
\[E = U + T = \frac{1}{2}kx^2 + \frac{1}{2}m\dot{x}^2 = \frac{1}{2}kA^2\cos^2(\omega t - \delta) + \frac{1}{2}mA^2\omega^2\sin^2(\omega t - \delta)\]
We have that $\omega^2 = \frac{k}{m}$ so:
\[\frac{k}{2}A^2\cos^2(\omega t - \delta) + \frac{k}{2}A^2\sin^2(\omega t - \delta) = \frac{kA^2}{2}\]
And hence the total energy is a constant; we can therefore see that $\od{E}{t} = 0$ and that the total energy is conserved.
\end{s}

\begin{p}
Damped oscillatons are described by the ODE $\ddot{x} + 2\beta\dot{x} + \omega_0^2x = 0$. Show that for overdamped motion, the decay "constant" (decay parameter) for a damped oscillator decreases with increasing friction. Sketch the decay parameters vs. $\beta$ for the whole range of $\beta$.
\end{p}
\begin{s}
We guess a solution of the form $x(t) = \exp(rt)$. We can therefore generate a characteristic equation for $r$, by substituting in the solution into the ODE and then cancelling out the exponential terms (as these can never be zero). Hence, we have:
\[r^2 + 2\beta r  + \omega_0^2 = 0\]
This is a quadratic equation with solutions:
\[r = -\beta \pm \sqrt{\beta^2 - \omega_0^2}\]
There are now different possibilities for the damping depending on the ratio of $\beta$ and $\omega_0$. For $\beta > \omega_0$, the oscillator is overdamped. For $\beta < \omega_0$, the oscillator is underdamped. For $\beta = \omega_0$, the oscillator is critically damped. Let us now consider the overdamped case. Then, we have that the discriminant in the equation above $\beta^2 - \omega_0^2$ is positive, and the general solution is the sum of decaying exponentials:
\[x(t) = C_1\exp(r_1 t) + C_2\exp(r_2 t) \]
where $r_1 = -\beta + \sqrt{\beta^2 - \omega^2}, r_2 = -\beta - \sqrt{\beta^2 - \omega^2}$. The dominant term will be the $\exp(r_1 t)$ term as this decays more slowly. Therefore, the decay parameter is:
\[-\beta + \sqrt{\beta^2 -\omega_0^2}\]
Which decreases with increasing $\beta$. We will also have a decay parameter for the underdamped case. In this case, the decay parameter is just $\beta$, as the discriminant is negative, and hence the solution $x(t)$ is composed of an oscillating part (the imaginary exponential part from the square root) and a real exponentially decaying part ($\exp(-\beta t)$). Hence the decay parameter increases linearly in this regime. Overall, we obtain a plot that looks like the follows:

Where the decay parameter is maximized when $\beta = \omega_0$, where we have critical damping.
\begin{center}
    \includegraphics[scale=0.5]{Lecture-9/w9-img1.png}
\end{center}
\end{s}

\begin{p}
Show that for critical damping, the solution $x(t) = te^{rt}$ solves the ODE $\ddot{x} + 2\beta\dot{x} + \omega_0^2x = 0$. Find $r$. Write the general solution.
\end{p}
\begin{s}
For critical damping, we have that $\beta = \omega_0$ and we can calculate $r$ to be:
\[r = -\beta \pm \sqrt{\beta^2 - \beta^2} = -\beta\]
Hence one solution is given by:
\[x_1(t) = C_1\exp(-\beta t)\]
And we check the Ansatz provided in the question to verify it as a second solution. The first time derivative is given by:
\[\dot{x} = \exp(rt) + rt\exp(rt)\]
And the second time derivative as:
\[\ddot{x} = r\exp(rt) + r\exp(rt) + r^2t\exp(rt) = 2r\exp(rt) + r^2t\exp(rt)\]
So substituting this into the ODE, with $r = -\beta$:
\[-2\beta\exp(-\beta t) + \beta^2t\exp(-\beta t) + 2\beta\left(\exp(-\beta t) - \beta t\exp(-\beta t)\right) + \beta^2t\exp(-\beta t) = 0\]
So we can see that this is indeed a solution! Hence the general solution is given by:
\[x(t) = C_1\exp(-\beta t) + C_2 t\exp(-\beta t)\]
\end{s}

\begin{p}
Find the condition on $C$ for $z(t) = Ce^{i\omega t}$ to be a solution to $\ddot{z} + 2\beta\dot{z} + \omega_0^2z = f_0e^{i\omega t}$. Express the coefficient $C$ as $Ae^{-i\delta}$ and find $A$ and $\delta$.
\end{p}
\begin{s}
Let us plug in $z(t)$ into the ODE:
\[(-\omega^2 + 2i\beta\omega + \omega_0^2)C\exp(i\omega t) = f_0\exp(i\omega t)\]
We may cancel out the exponentials on both sides:
\[(-\omega^2 + 2i\beta\omega + \omega_0^2) =f_0\]
Hence we find:
\[C = \frac{f_0}{-\omega^2 + 2i\beta\omega + \omega_0^2} = A\exp(i\delta)\]
We have that $A^2 = CC^*$ and so:
\[A^2 = \frac{f_0}{-\omega^2 + 2i\beta\omega + \omega_0^2}\frac{f_0}{-\omega^2 - 2i\beta\omega + \omega_0^2} = \frac{f_0^2}{(\omega_0^2 - \omega^2)^2 + 4\beta^2\omega^2}\]
To get the phase, we see that:
\[f_0\exp(i\delta) = A(\omega_0^2 - \omega^2 + 2i\beta\omega)\]
And solving (using some knowledge of complex numbers and extracting their phase) we get:
\[\delta = \arctan(\frac{\Im}{\Re}) = \arctan(\frac{2\beta \omega}{\omega_0^2 - \omega^2})\]
\end{s}

\begin{p}
Write the general solution to $\ddot{x} + 2\beta\dot{x} + \omega_0^2x = f_0\cos(\omega t)$ for the underdamped case. What are the two undetermined constants?
\end{p}
\begin{s}
Writing the general solution, we have:
\[x(t) = A\cos(\omega t -\delta) + C_1\exp(r_1 t) + C_2\exp(r_2 t)\]
Where the first term is the particular solution (comes from the driving) and the exponentials come from the homogenous solution. The former is the long-term oscillatory behavior, the latter is the transient solution (the exponentials decay away with time).
\end{s}

\begin{p}
Show that the Q-factor given by the ratio of the width to the mean of the resonance curve is equal to $\pi$ times the number of oscillations in one decay time.
\end{p}
\begin{s}
When $\omega \sim \omega_0$ (when the driving frequency approaches the natural frequency), we notice a resonance phenomenon, where the amplitude of the driven oscillator gets very large (technically it is slightly off from $\omega = \omega_0$, but to good approximation it is at the natural frequency of the system). This is pictured below:
\begin{center}
    \includegraphics[scale=0.5]{Lecture-9/w9-img2.png}
\end{center}
We can also consider the width of the resonance peak. It is defined as:
\[Q = \frac{\omega_0}{2\beta}\]
Stronger damping implies a smaller quality factor and a narrower peak, and weak damping implies a larger quality factor and a broadened peak. To prove the claim provided in the question, we consider that the decay time is given by $\tau = \frac{1}{\beta}$ and the period is $T = \frac{2\pi}{\omega_0}$, so plugging this in we can immediately see that:
\[Q = \frac{\omega_0}{2\beta} = \frac{\frac{1}{\beta}\pi}{\frac{2\pi}{\omega_0}} = \pi\frac{\tau}{T}\]
which is the desired result.
\end{s}

\begin{p}
Find the phase shift at resonance when the driving frequency $\omega$ is varied. Sketch the phase shift $\delta$ vs. $\omega$.
\end{p}
\begin{s}
The phase shift is given by $\delta = \frac{\pi}{2}$ (perfectly out of phase). We can see this as the phase shift is given above by:
\[\delta = \arctan(\frac{2\beta\omega}{\omega_0^2 - \omega^2})\]
And at resonance we have $\omega \sim \omega_0$, so therefore the argument fo the arctan goes to infinity, and hence the value of $\delta$ goes to $\frac{\pi}{2}$.
\end{s}
\end{document}


\hypertarget{haskell}{%
\section{Haskell - Recursive Functions}\label{haskell}}

In Haskell, functions can also be defined in terms of themselves. Such
functions are called recursive.

\begin{itemize}
\tightlist
\item
  Some functions, such as factorial, are simpler to define in terms of
  other functions.
\item
  As we shall see, however, many functions can naturally be defined in
  terms of themselves.
\item
  Properties of functions defined using recursion can be proved using
  the simple but powerful mathematical technique of induction.
\end{itemize}

\hypertarget{recursion-on-lists}{%
\subsection{Recursion on Lists}\label{recursion-on-lists}}

\begin{lstlisting}[language=Haskell]
product :: Num a -> [a] -> a
product [] = 1
product (n:ns) = n * product ns

In execution:

product [2,3,4]
2 * product [3,4]
2 * (3 * product [4])
2 * (3 * (4 * product []))
2 * (3 * (4 * 1))
24

--or
-- The maximum function takes a list of things that can be ordered (e.g. instances of the Ord typeclass) and returns the biggest of them.

maximum' :: (Ord a) => [a] -> a
maximum' [] = error "maximum of empty list"
maximum' [x] = x
maximum' (x:xs)
    | x > maxTail = x
    | otherwise = maxTail
    where maxTail = maximum' xs
\end{lstlisting}

\hypertarget{multiple-arguments}{%
\subsection{Multiple Arguments}\label{multiple-arguments}}

Functions with more than one argument can also be defined using
recursion.

\begin{lstlisting}[language=Haskell]
zip :: [a] -> [b] -> [(a,b)]
zip []    _       = []
zip  _    []      = []
zip (x:xs) (y:ys) = (x,y) : zip xs ys
\end{lstlisting}

\subsection{Some Examples}

\begin{lstlisting}[language=Haskell]
take' :: (Num i, Ord i) => i -> [a] -> [a]
take' n _
    | n <= 0   = []
take' _ []     = []
take' n (x:xs) = x : take' (n-1) xs

reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]
\end{lstlisting}

\clearpage
\subsection{Quick Sort}

We have a list of items that can be sorted. Their type is an instance of the \textbf{Ord} typeclass. The edge condition is the empty list. Now a sorted list is a list that has all the values smaller than (or equal to) the head of the list in front (and those values are sorted), then comes the head of the list in the middle and then come all the values that are bigger than the head (they're also sorted).

\begin{lstlisting}[language=Haskell]
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
    let smallerSorted = quicksort [a | a <- xs, a <= x]
        biggerSorted = quicksort [a | a <- xs, a > x]
    in  smallerSorted ++ [x] ++ biggerSorted
\end{lstlisting}

So if we have, say [5,1,9,4,6,7,3] and we want to sort it, this algorithm will first take the head, which is 5 and then put it in the middle of two lists that are smaller and bigger than it. So at one point, you'll have [1,4,3] ++ [5] ++ [9,6,7]. We know that once the list is sorted completely, the number 5 will stay in the fourth place since there are 3 numbers lower than it and 3 numbers higher than it. Now, if we sort [1,4,3] and [9,6,7], we have a sorted list! We sort the two lists using the same function. Eventually, we'll break it up so much that we reach empty lists and an empty list is already sorted in a way, by virtue of being empty.

\clearpage


\chapter{Dimension Reduction}
\emph{“你们都不是49年的国军，你们是50年的国军。”}
\newpage

\section{Principal Component Analysis}
    \emph{aka. Discrete Karhunen Loeve Transform; Hotelling Transform}

    Let $y \in \mathbb{R}^K$ be a feature vector computed from $x \in \mathbb{R}^D$ where $K \ll D$. PCA determines an orthogonal matrix $W \in \mathbb{R}^{D \times K}$ s.t.
    \[ y = W^Tx \]

    Assume in this section that $x$ has a distribution with mean $\mu=0$ and covariance matrix $\Sigma$.

    \subsection{Objective Funtion}
        PCA minimizes the reconstruction error between original $x$ and reconstructed $\hat{x}$.

        Notice that $W$ is orthogonal, so $x$ can be reconstructed by
        \[ \hat{x} = Wy \]

        Let the reconstruction error be
        \[ \epsilon = x - \hat{x} = x - WW^Tx \]

        We want to minimize the reconstruction error
        \[ \|\epsilon\|^2 = \epsilon^T\epsilon = x^Tx - x^TWW^Tx \]

        The minimization is performed over all possible $x$
        \[ \int p(x)\epsilon(x)^T\epsilon(x)\mathrm{d}x \]

        \[ \mathbb{E}[\epsilon^T\epsilon] = \mathbb{E}[x^Tx] - \mathbb{E}[x^TWW^Tx]\]

    \subsection{Simple Case}
        If $K=1$, $w$ is a vector and $y$ is a scalar.
        \[\mathbb{E}[\epsilon^T\epsilon] = \mathbb{E}[x^Tx]-w^T\mathbb{E}[xx^T]w = \mathbb{E}[x^Tx] - w^T \Sigma w\]
        where $\Sigma = XX^T$ (recall that $X$ is assumed to have zero mean).

        We maximize the normalized second term
        \[ \max_w \quad J \triangleq \frac{w^TXX^Tw}{w^Tw} \]

        Or it can also be formulated as a equality constrained maximization and solved by Lagrangian.

        The solution is
        \[ XX^Tw=Jw \]

        So the problem becomes finding the eigenvalues of $XX^T$, to maximize $J$, we find the largest eigenvalue of $XX^T$.

        Other dimensions turn out to be the remaining eigenvectors.

    \subsection{Geometric Interpretation}
        \begin{itemize}
            \item PCA is a shift and rotation of axis.
            \item $w_1$ is the direction of greatest elongation
            \item $w_2$ is the second largest elongation that is orthogonal to $w_1$
        \end{itemize}

\section{Multi-Dimensional Scaling}
    MDS aims to keep the distances of samples in the mapped space that same as the distances in the original space.

    In this section we also assume the data samples have $\mu=0$.

    \[ \min_{\hat{x}} \left(\sum_{i<j}\left( \|\hat{x}_i-\hat{x}_j\| - d_{ij} \right)^2\right)^{1/2} \]
    where $\hat{x}$ are mapped (instead of reconstructed) samples.

    Let $X$ be the unknown \emph{dimension-reduced} samples. Let $T=XX^T$ and $t_{ij}=\hat{x}_i^T\hat{x}_j$.

    The distance between $\hat{x}_i$ and $\hat{x}_j$ is given by
    \[d_{ij}^2 = (\hat{x}_i-\hat{x}_j)^T(\hat{x}_i-\hat{x}_j)\]

    Solving for $t_{ij}$ yields
    \[ t_{ij} = -\frac{1}{2}(d_{ij}^2\hat{x}_i^2-\hat{x}_j^2) \]

    We also have
    \[\sum_j d_{ij}^2 = n\hat{x}_i^2 + \sum_j\hat{x}_j^2 - 2\hat{x}_i\sum_j\hat{x}_j = n\hat{x}_i^2 + \sum_j\hat{x}_j^2\]
    \[\sum_i d_{ij}^2 = n\hat{x}_j^2 + \sum_i\hat{x}_i^2 - 2\hat{x}_j\sum_i\hat{x}_i = n\hat{x}_j^2 + \sum_i\hat{x}_i^2\]
    \[\sum_{i}\sum_{j}d_{ij}^2=n\sum_i\hat{x}_i^2 + n\sum_j\hat{x}_j^2 \]
    Again recall that the data are assumed to have zero mean so the sum over all data samples yields zero.

    So we can solve for $t_{ij}$
    \[ t_{ij} = -\frac{1}{2}\left(d_{ij}^2-\frac{1}{n}\sum_kd_{ik}^2-\frac{1}{n}\sum_kd_{kj}^2-\frac{1}{n}\sum_{k}\sum_{l}d_{kl}^2\right) \]
    where $d_{ij}$ can be computed from the original dataset.

    Since $T=XX^T$, we can solve for $X$ by decomposing $T$.
    \[T = U\Lambda U^T = U\Lambda^{1/2}\Lambda^{1/2}U^T\]

    Therefore $X=U\Lambda^{1/2}$

\section{Non-Linear Dimension Reduction}
    \subsection{ISOmetric feature MAPping}
        Uses the geodesic distance (shortest distance on a plane) instead of Euclidean distance. The remaining work is similar to MDS and is pigeoned in this note.

    \subsection{Locally Linear Embedding}
        Assumes that a data sample can be represented by some linear combination of its local neighbors\footnote{This assumption is reasonable because the distribution can be somehow ``linearized'' in a sufficiently small area, just like derivatives.}, and that this relationship does not change after dimension reduction.

        LLE can basically be divided into two steps. We first solve for the locally linear combination relationship\footnote{Actually we will first have to find the local nearest neighbours for each data sample $x_i$.} in the original space (solve for a coefficient matrix $W$), and then reconstruct the relationship in a mapped space (solve for mapped data $Y$).

        \subsubsection{Solving Linear Combination}
        In the original space, let $x_j$ be some neighbors of $x_i$. Let $W \in \mathbb{R}^{N \times N}$.
        \[ \epsilon(W) = \sum_i \left|x_i - \sum_jW_{ij}x_j\right|^2 \]
        \begin{align*}
            \min_W &\quad \epsilon(W)\\
            \text{s.t.} &\quad W_{ij} = 0 \quad x_j \notin \mathcal{N}(x_i)\\
            &\quad \sum_j W_{ij}=1
        \end{align*}

        Can be solved by Lagrangian multipliers.

        \subsubsection{Solving Mapping}
        In the mapped space
        \[ \phi(y) = \sum_i\left| y_i - \sum_j W_{ij}y_j \right|^2 \]
        \begin{align*}
            \min_W &\quad \phi(y)\\
            \text{s.t.} &\quad \sum_i y_i = 0\\
            &\quad \frac{1}{N} YY^T = I
        \end{align*}
        where $Y$'s columns are $y_i$.

        To make the problem easier, we convert it into a quadratic form. Define an error matrix
        \[ \delta = Y-YW \triangleq [\Delta y_1,\Delta y_2,\cdots,\Delta y_N]\]

        The total error is given by
        \[ \sum_{i=1}^N \Delta y_i^T \Delta y_i \]

        Notice that
        \[ \delta^T\delta = \begin{bmatrix}
            \Delta y_1^T \Delta y_1 & \Delta y_1^T \Delta y_2 & \cdots & \Delta y_1^T \Delta y_N\\
            \Delta y_2^T \Delta y_1 & \Delta y_2^T \Delta y_2 & \cdots & \Delta y_2^T \Delta y_N\\
            \vdots & \vdots & \ddots & \vdots\\
            \Delta y_N^T \Delta y_1 & \Delta y_N^T \Delta y_2 & \cdots & \Delta y_N^T \Delta y_N
        \end{bmatrix} \]

        So the error can be expressed as
        \[ Tr[\delta^T\delta] = Tr[(Y(I-W))^T(Y(I-W))] = Tr[(I-W)^TY^TY(I-W)] = Tr[Y^T(I-W)^T(I-W)Y] \]

        Let $M = (I-W)^T(I-W)$, the objective function becomes
        \[ \min Tr(Y^TMY) \]

        So we can solve for $Y$ by Lagrangian multipliers.


\documentclass{article}
\usepackage{eecstex}
\usepackage{pgfplots}

\title{EE 123 HW 02}
\author{Bryan Ngo}
\date{2022-01-29}

\begin{document}

\maketitle

\setcounter{section}{2}

\section{}

\begin{equation}
    a^n u[n] \iff \frac{1}{1 - ae^{-j \omega}}, \ |a| < 1
\end{equation}

\subsection{}

\begin{equation}
    x[n] = -b^n u[-n - 1] =
    \begin{cases}
        -b^n & n \leqslant -1 \\
        0 & n \geqslant 0
    \end{cases}
\end{equation}
Using the definition of the DTFT,
\begin{align}
    X(e^{j \omega}) &= \sum_{k \in \Z} -b^k u[-k - 1] e^{-j \omega k} \\
    &= -\sum_{k \leqslant -1} b^k e^{-j \omega k}
\end{align}
Letting \(k' = -k\),
\begin{align}
    X(e^{j \omega}) &= \sum_{k' \geqslant 1} -b^{-k'} e^{j \omega k'} \\
    &= \sum_{k \geqslant 0} -(b^{-1} e^{j \omega})^k - 1 \\
    &= 1 - \frac{1}{1 - b e^{j \omega}} \\
    &= \frac{\cancel{1} - b e^{j \omega} - \cancel{1}}{1 - b e^{j \omega}} \cdot \frac{-b e^{-j \omega}}{-b e^{-j \omega}} \\
    &= \frac{1}{1 - b e^{-j \omega}}
\end{align}
where \(|b^{-1}| < 1 \implies |b| > 1\).

\subsection{}

\begin{align}
    Y(e^{j \omega}) &= 2e^{-j \omega} \frac{1}{1 - (-2) e^{-j \omega}} \\
    \overset{\mathcal{F}^{-1}}{\implies} y[n] &= 2 (-(-2)^{n - 1} u[-(n - 1) - 1]) \\
    &= (-2)^n u[-n]
\end{align}

\newpage
\section{}

\begin{equation}
    H(z) = \frac{1 - z^{-1}}{1 - 0.25z^{-2}} = \frac{1 - z^{-1}}{(1 - 0.5z^{-1}) (1 + 0.5z^{-1})}
\end{equation}

\subsection{}

Using the \(z\)-transform multiplication property,
\begin{equation}
    Y(z) = H(z) X(z) = \frac{\cancel{1 - z^{-1}}}{(1 - 0.5z^{-1}) (1 + 0.5z^{-1}) \cancel{(1 - z^{-1})}} = \frac{1}{(1 - 0.5z^{-1}) (1 + 0.5z^{-1})}
\end{equation}
Then, using partial fraction decomposition,
\begin{align}
    Y(z) &= \frac{1}{(1 - 0.5z^{-1}) (1 + 0.5z^{-1})} = \frac{A}{1 - 0.5z^{-1}} + \frac{B}{1 + 0.5z^{-1}} \\
    &= 1 = A(1 + 0.5z^{-1}) + B(1 - 0.5z^{-1}) \\
\end{align}
Letting \(z = -0.5\), we get \(B = \frac{1}{2}\).
Letting \(z = 0.5\), we get \(A = \frac{1}{2}\).
Then,
\begin{align}
    Y(z) &= \frac{1}{2} \frac{1}{1 - 0.5z^{-1}} + \frac{1}{2} \frac{1}{1 + 0.5z^{-1}} \\
    \overset{\mathcal{Z}^{-1}}{\implies} y[n] &= \frac{1}{2} \left(\frac{1}{2}\right)^n u[n] + \frac{1}{2} \left(-\frac{1}{2}\right)^n u[n]
\end{align}

\subsection{}

\begin{equation}
    y[n] = \delta[n] - \delta[n - 1] \overset{\mathcal{Z}}{\implies} Y(z) = 1 - z^{-1} = H(z) X(z)
\end{equation}
meaning that \(X(z) = 1 - 0.25z^{-2} = (1 - 0.5z^{-1}) (1 + 0.5z^{-1})\).
By definition of the \(z\)-transform,
\begin{equation}
    x[n] = \delta[n] - \frac{1}{4} \delta[n - 2]
\end{equation}

\subsection{}

Treating the input as the real part of \(z = e^{j 0.5 \pi}\),
\begin{equation}
    H(e^{j 0.5 \pi}) = \frac{1 - e^{-j 0.5 \pi}}{1 - 0.25e^{-j\pi}} = 0.8 \sqrt{2} e^{j \frac{\pi}{4}}
\end{equation}
Meaning that the final output is
\begin{equation}
    y[n] = 0.8 \sqrt{2} \cos\left(0.5 \pi n + \frac{\pi}{4}\right)
\end{equation}

\newpage
\section{}

\begin{align}
    x[n] &= -\frac{1}{3} \left(\frac{1}{2}\right)^n u[n] - \frac{4}{3} 2^n u[-n - 1] \\
    Y(z) &= \frac{1 - z^{-2}}{\left(1 - \frac{1}{2} z^{-1}\right) (1 - 2z^{-1})}
\end{align}

\subsection{}

\begin{equation}
    X(z) = -\frac{1}{3} \frac{1}{1 - \frac{1}{2} z^{-1}} + \frac{4}{3} \frac{1}{1 - 2z^{-1}}
\end{equation}

\subsection{}

\begin{equation}
    R_y: \frac{1}{2} < |z| < 2
\end{equation}

\subsection{}

Simplifiying \(X(z)\),
\begin{align}
    X(z) &= \frac{1}{3} \frac{-(1 - 2z^{-1}) + 4 \left(1 - \frac{1}{2} z^{-1}\right)}{\left(1 - \frac{1}{2} z^{-1}\right) (1 - 2z^{-1})} \\
    &= \frac{1}{3} \frac{-1 + \cancel{2z^{-1}} + 4 - \cancel{2z^{-1}}}{\left(1 - \frac{1}{2} z^{-1}\right) (1 - 2z^{-1})} \\
    &= \frac{1}{\left(1 - \frac{1}{2} z^{-1}\right) (1 - 2z^{-1})} \\
    \implies Y(z) &= (1 - z^{-2}) X(z) = X(z) - z^{-2} X(z) \\
    \overset{\mathcal{Z}^{-1}}{\implies} y[n] &= x[n] - x[n - 2]
\end{align}

\subsection{}

\begin{equation}
    H(z) = \frac{Y(z)}{X(z)} = 1 - z^{-2} \overset{\mathcal{Z}^{-1}}{\implies} h[n] = \delta[n] - \delta[n - 2]
\end{equation}

\newpage
\section{}

\begin{align}
    X(z) &= \frac{z^{-2}}{1 - 2.3z^{-1} + 1.6z^{-2} - 0.3z^{-3}} = \frac{2.04}{1 + 0.3z^{-1}} - \frac{3.47}{1 - z^{-1}} + \frac{1.43}{(1 - z^{-1})^2} \\
    \overset{\mathcal{Z}^{-1}}{\implies} x[n] &= (-0.3)^n u[n] - 3.47 u[n] + 1.43 (n + 1) u[n + 1]
\end{align}

\newpage
\section{}

\begin{enumerate}
    \item System A, causal, stable, ROC: \(|z| > 0.9\)
    \item System B, non-causal, stable, ROC: \(|z| < 1.111\)
    \item System A, non-causal, unstable, ROC: \(|z| < 0.9\)
\end{enumerate}

\newpage
\section{}

\begin{equation}
    Z(e^{j \omega}) = \frac{1}{2\pi} \int_{-\pi}^\pi X(e^{j \theta}) Y(e^{j (\omega - \theta)}) \, d\theta
\end{equation}

\subsection{}

\begin{align}
    Y(e^{j \omega}) &= \pi \sum_{k = -\infty}^\infty \delta(\omega - \pi + 2\pi k) + \delta(\omega + \pi + 2\pi k) \\
    X(e^{j \omega}) \ast Y(e^{j \omega}) &= \frac{1}{2} \int_{-\pi}^\pi X(e^{j \theta}) \sum_{k \in \Z} \delta((\omega - \theta) - \pi + 2\pi k) + \delta((\omega - \theta) + \pi + 2\pi k) \, d\theta \\
    &= \frac{1}{2} \sum_{k \in \Z} \int_{-\pi}^\pi X(e^{j \omega}) (\delta(\omega - \theta - \pi + 2\pi k) + \delta(\omega + \theta + \pi + 2\pi k)) \, d\theta \\
    &= \frac{1}{2} \sum_{k \in \Z} (X(e^{j (\omega - \pi + 2\pi k)}) + X(e^{j (\omega + \pi + 2\pi k)}))
\end{align}
\begin{center}
    \begin{tikzpicture}
        \begin{axis}[
            xlabel={\(\frac{\omega}{\pi}\)}, ylabel={\(Z(e^{j \omega})\)},
            title={DTFT of Product},
            axis lines=middle,
        ]
        \addplot[color=blue] table[
            col sep=comma,
            x=index, y=8a
        ]{q8.csv};
        \end{axis}
    \end{tikzpicture}
\end{center}

\subsection{}

\begin{align}
    Y(e^{j \omega}) &= \pi \sum_{k = -\infty}^\infty \delta\left(\omega - \frac{\pi}{2} + 2\pi k\right) + \delta\left(\omega + \frac{\pi}{2} + 2\pi k\right) \\
    X(e^{j \omega}) \ast Y(e^{j \omega}) &= \frac{1}{2} \sum_{k \in \Z} \left(X\left(e^{j \left(\omega - \frac{\pi}{2} + 2\pi k\right)}\right) + X\left(e^{j \left(\omega + \frac{\pi}{2} + 2\pi k\right)}\right)\right)
\end{align}
\begin{center}
    \begin{tikzpicture}
        \begin{axis}[
            xlabel={\(\frac{\omega}{\pi}\)}, ylabel={\(Z(e^{j \omega})\)},
            title={DTFT of Product},
            axis lines=middle,
        ]
        \addplot[color=blue] table[
            col sep=comma,
            x=index, y=8b
        ]{q8.csv};
        \end{axis}
    \end{tikzpicture}
\end{center}

\subsection{}

\begin{align}
    Y(e^{j \omega}) &= \pi \sum_{k = -\infty}^\infty \delta\left(\omega - \frac{\pi}{4} + 2\pi k\right) + \delta\left(\omega + \frac{\pi}{4} + 2\pi k\right) + \delta\left(\omega - \frac{3\pi}{4} + 2\pi k\right) + \delta\left(\omega + \frac{3\pi}{4} + 2\pi k\right) \\
    X(e^{j \omega}) \ast Y(e^{j \omega}) &= \frac{1}{2} \sum_{k \in \Z} \left(X\left(e^{j \left(\omega - \frac{\pi}{2} + 2\pi k\right)}\right) + X\left(e^{j \left(\omega + \frac{\pi}{2} + 2\pi k\right)}\right)\right)
\end{align}
\begin{center}
    \begin{tikzpicture}
        \begin{axis}[
            xlabel={\(\frac{\omega}{\pi}\)}, ylabel={\(Z(e^{j \omega})\)},
            title={DTFT of Product},
            axis lines=middle,
        ]
        \addplot[color=blue] table[
            col sep=comma,
            x=index, y=8c
        ]{q8c.csv};
        \end{axis}
    \end{tikzpicture}
\end{center}

\subsection{}

\begin{align}
    Y(e^{j \omega}) &= \pi \sum_{k = -\infty}^\infty \cancelto{1}{e^{j \frac{\pi}{2}}} \delta(\omega - \pi + 2\pi k) + \cancelto{-1}{e^{-j \frac{\pi}{2}}} \delta(\omega + \pi + 2\pi k) \\
    X(e^{j \omega}) \ast Y(e^{j \omega}) &= \frac{1}{2} \sum_{k \in \Z} (X(e^{j (\omega - \pi + 2\pi k)}) - X(e^{j (\omega + \pi + 2\pi k)}))
\end{align}
\begin{center}
    \begin{tikzpicture}
        \begin{axis}[
            xlabel={\(\frac{\omega}{\pi}\)}, ylabel={\(Z(e^{j \omega})\)},
            title={DTFT of Product},
            axis lines=middle,
        ]
        \addplot[color=blue] table[
            col sep=comma,
            x=index, y=8d
        ]{q8.csv};
        \end{axis}
    \end{tikzpicture}
\end{center}

\newpage
\section{}

\begin{equation}
    H(e^{j \omega}) =
    \begin{cases}
        j & \omega \in (-\pi, 0) \\
        0 & \omega = 0 \\
        -j & \omega \in (0, \pi)
    \end{cases}
\end{equation}

\subsection{}

From Table 2.1 of O\&S, the symmetry properties of the DTFT imply that the Hilbert filter impulse response is purely \emph{real and odd}.

\subsection{}

\begin{align}
    X(e^{j \omega}) &= \pi (\delta(\omega - \omega_0) + \delta(\omega + \omega_0)) \\
    Y(e^{j \omega}) &= -j \pi (\delta(\omega - \omega_0) - \delta(\omega + \omega_0)) \\
    \overset{\mathcal{F}^{-1}}{\implies} y[n] &= \sin(\omega_0 n)
\end{align}

\subsection{}

\begin{align}
    Y(e^{j \omega}) &= H(e^{j \omega})^2 X(e^{j \omega}) =
    \begin{cases}
        -X(e^{j \omega}) & \omega \in (-\pi, 0) \\
        0 & \omega = 0 \\
        -X(e^{j \omega}) & \omega \in (0, \pi)
    \end{cases} \\
    &= -X(e^{j \omega}) \overset{\mathcal{F}^{-1}}{\implies} y[n] = -x[n]
\end{align}

\subsection{}

\begin{center}
    \includegraphics[width=0.6\textwidth]{q9d.png}
\end{center}
where \(\mathcal{H}\) is the Hilbert transform.

\end{document}


%\section{Stabilization and Weak Formulation}
\label{app:stab}

This appendix details the weak formulation of the Navier Stokes
equations instantiated in the software GRINS, and provides a
derivation of the $\tau$ stabilization terms shown in
Equation~\ref{eq:tau}.

In brief, our process is the following:

\begin{itemize}
 \item Cast Navier Stokes + Boussinesq equations into weak form
 \item Prepare as an operator $L\,{\bf c}={\bf f}$
 \item Calculate Fr\'echet derivative
 \item Separate into differential (P) and constant (Z) components,
       $L'[{\bf c}] = P + Z$
 \item Choose stabilization operator such that $S = -P^*$
 \item Then stabilization has form, $a_h({\bf c},{\bf \phi}) = a({\bf c},{\bf \phi}) + \langle
       L{\bf c},S{\bf \phi} \rangle_\tau$
\end{itemize}

This is essentially the least-squares stabilization proposed by Hughes
and extended to natural convection by Becker and Braack.

%
% start the real work
%

\section{Weak Formulation of the Equations of Interest}

We begin with the incompressible Navier-Stokes equations with Boussinesq
buoyancy,
\begin{align}
 \nabla \cdot {\bf u} &= \, 0 \label{eq_cont}\\
 \frac{\partial {\bf u}}{\partial t} + {\bf u} \cdot \nabla {\bf u} &= -\frac{1}{\rho}
 \nabla p + \nu \nabla^2 {\bf u} + g \frac{T'}{T_0} \label{eq_mom}\\
 \rho c_p \frac{\partial T}{\partial t} + {\bf u} \cdot \nabla T &= \nabla
 \cdot (k \nabla T) \label{eq_energy}
\end{align}
e.g. the continuity, momentum and energy equations, respectively. Our
state vector is ${\bf c} =  \left[p,{\bf u},T \right]$. To cast these into
weak form we multiply by appropriate test
functions ${\bf \phi} = \left[q,{\bf v},w \right] \in H^1_0(\Omega)$ and
integrate over the domain, $\Omega \in \mathbb{R}^n$. Our system of
equations now appears as,
\begin{align}
  \bigintsss_\Omega q \nabla \cdot {\bf u} \, dx &= 0 \\
 \bigintsss_\Omega \dot {\bf u} \cdot {\bf v} \, dx +
 \bigintsss_\Omega  ({\bf u} \cdot \nabla) \, {\bf u} \cdot {\bf v} \, dx &=
 \bigintsss_\Omega \frac{p}{\rho} \nabla \cdot {\bf v} \, dx -
 \bigintsss_\Omega \nu \, \nabla {\bf u} \cdot \nabla {\bf v}
 \,dx + \bigintsss_\Omega g \frac{T'}{T_0} \cdot {\bf v} \, dx \\
 \rho c_p \bigintsss_\Omega \dot T \cdot w \, dx + \bigintsss_\Omega ({\bf u}
 \cdot \nabla) T \cdot w \, dx  &= -\bigintsss_\Omega (k \nabla T) \cdot
 \nabla w \, dx
\end{align}
%
where an ``over-dot'' denotes time differentiation, e.g. $\dot {\bf u} =
\frac{\partial {\bf u}}{\partial t}$. Note that both the pressure term as well
as the viscous term were integrated by parts to reduce the required
order of the solution on those state variables.

The inner product is abbreviated by the shorthand notation $({\bf u},{\bf v}) =
\bigintsss_\Omega {\bf u}\cdot {\bf v}\, dx $, giving our equations the form,
\begin{align}
 (\nabla \cdot {\bf u}, q) &= 0 \\
 (\dot {\bf u},{\bf v}) + ({\bf u} \cdot \nabla {\bf u}, {\bf v}) -
 (p,\nabla \cdot {\bf v}) + (\nu \, \nabla
 {\bf u}, \nabla {\bf v}) &= (g \frac{T'}{T_0},{\bf v}) \\
 \rho c_p (\dot T,w) + ({\bf u} \cdot \nabla T,w) + (k \nabla T,\nabla w) &= 0.
\end{align}
%
This defines our weak form operator, $ a({\bf c},{\bf \phi})$. Our full equations will
also include a stabilization term such that,
\begin{equation}
 a_h({\bf c},{\bf \phi}) = a({\bf c},{\bf \phi}) +  \langle L\,{\bf c},S{\bf \phi} \rangle_\tau.
\end{equation}
%
The subsequent section will define the operators L and S, so that we
might then fully define the stabilization term $\langle L\,{\bf c},S{\bf \phi}
\rangle_\tau$.

%
% section
%
\section{The Stabilization Operators, L and S}

To form the stabilization terms,

\begin{equation}
 \langle L\,{\bf c},S{\bf \phi} \rangle_\tau
\end{equation}

we must define the operators L and S. The operator L is simply the PDEs
in Equations \ref{eq_cont} - \ref{eq_energy} written in operator form. S is
defined as the negative adjoint of the differential terms in L, e.g.
\begin{align}
 L'[{\bf c}] = P + Z \\
 S = -P^*.
\end{align}
Where P are the differential terms, and Z the constant terms.

Our objective is now to construct the adjoint operator of L. This is
accomplished using the Fr\'echet derivative, which defines the
functional derivative on L. In general this is accomplished by taking
the first variation of a function $\Pi({\bf u})$ around a base state, ${\bf u}$,
\begin{equation}
 \delta\, \Pi({\bf u}) = \lim_{\epsilon \to 0} \frac{\Pi({\bf
  u}+\epsilon \, \hat {\bf u}) -
  \Pi({\bf u})}{\epsilon} =
  \frac{\partial \Pi({\bf u} +\epsilon \, \hat {\bf u})}{\partial \epsilon}
  \bigg|_{\epsilon = 0}
\end{equation}
$\forall \hat {\bf u}, \epsilon > 0$ with ${\bf u} + \epsilon \, \hat {\bf u} \in
H^1_0(\Omega)$. This is recognizable as the G\^{a}teaux
derivative of the functional.

We now consider the first variation of state for the momentum equation
term by term. The convective term is,
\begin{align}
 \frac{\partial}{\partial \epsilon} ({\bf u} + \epsilon \, \hat {\bf u}) &\cdot \nabla
  ({\bf u} + \epsilon \hat {\bf u}) \\
 = \lim_{\epsilon \to 0} \, \hat {\bf u} &\cdot \nabla ({\bf u} + \epsilon \,\hat {\bf u}) \\
 = \hat {\bf u} & \cdot \nabla {\bf u} \\
 = - {\bf u} &\cdot \nabla \hat {\bf u}
\end{align}
and the viscous term is,
\begin{align}
 \frac{\partial}{\partial \epsilon} \nabla^2 ({\bf u} + \epsilon \, \hat {\bf u}) \\
 = \nabla^2 \hat {\bf u}
\end{align}
while the buoyancy term is,
\begin{align}
 \delta \left(-g \frac{T'}{T_0}\right) &= \delta \left( -g
 \frac{T-T_0}{T_0} \right) \\
 &= -g \frac{\partial}{\partial \epsilon} \left( \frac{T-T_0+\epsilon
 \hat T}{T_0} \right) \\
 &= -g \left( \frac{\hat T}{T_0} \right)
\end{align}
%
%
%Lagrangian is therefore, $\mathcal{L}$
and thus the full adjoint equation for momentum appears as,
\begin{align}
 - {\bf u} &\cdot \nabla \hat {\bf u} - \nabla^2 \hat {\bf u} = -\frac{1}{\rho} \nabla p.
\label{eq_adjmom}
\end{align}
%
The continuity equation is straightforward,
\begin{align}
 \frac{\partial}{\partial \epsilon} \nabla \cdot ({\bf u} + \epsilon \,
 \hat {\bf u}) &= 0, \\
\nabla \cdot \hat {\bf u} &= 0.
\label{eq_adjcont}
\end{align}
%
Finally, consider the convective term of the energy equation,
\begin{align}
 \frac{\partial}{\partial \epsilon} {\bf u} \cdot \nabla (T + \epsilon
 \, \hat T)
 = {\bf u} \cdot \nabla \hat T
\end{align}
and the thermal diffusion term,
\begin{align}
 \frac{\partial}{\partial \epsilon} \cdot (-k \nabla (T + \epsilon \hat
 T)) = \nabla \cdot (-k \nabla \hat T).
\end{align}
The full adjoint energy equation is therefore,
\begin{align}
 {\bf u} \cdot \nabla \hat T + \nabla \cdot (k \nabla \hat T) = 0.
\label{eq_adjen}
\end{align}

We are now in a position to define the matrices L and S. L comes
directly from the PDEs in Equations \ref{eq_cont} - \ref{eq_energy} and is
defined as thus,

\begin{equation}
\renewcommand\arraystretch{2}
 L =
  \begin{pmatrix}
    0 & \nabla \cdot () & 0   \\
    \nabla \,() & {\bf u} \cdot \nabla() - \nu \nabla^2() & -g \frac{()}{T_0}  \\
    0 & 0 & {\bf u} \cdot \nabla() - \nabla \cdot (k \nabla() \,)
  \end{pmatrix}.
\end{equation}
%
While the S matrix is constructed from Equations~\ref{eq_adjmom},
\ref{eq_adjcont}, and \ref{eq_adjen}, and must be,
\begin{equation}
\renewcommand\arraystretch{2}
 S = -P^* =
  \begin{pmatrix}
    0 & \nabla \cdot () & 0   \\
    \nabla \,() & {\bf u} \cdot \nabla() + \nu \nabla^2() &  -g \frac{()}{T_0}  \\
    0 & 0 & {\bf u} \cdot \nabla() + \nabla \cdot k \nabla()
  \end{pmatrix}.
\end{equation}

%
% tau!
%
\section{Tau Stabilization Terms}

Finally, we may now form the $\tau$ stabilization terms,
\begin{equation}
 \langle L\, {\bf c},S{\bf \phi} \rangle_\tau.
\end{equation}
Where the operator $ \langle \cdot,\cdot \rangle_\tau. $ is shorthand
and denotes
\begin{equation}
 \langle {\bf u},{\bf v} \rangle_\tau = \sum_K \tau_K ({\bf u},{\bf v})_K.
\end{equation}
Where $K$ denotes the FEM cells. Now, through what Becker and Braack
contemptibly referred to as ``elementary calculus'', we arrive at our
stabilization terms,
\begin{align*}
 \langle L\,{\bf c},S{\bf \phi} \rangle_\tau = \sum_K \{ \quad &\tau_p (\nabla \cdot {\bf u},
 \nabla \cdot {\bf v}) \\
 +\quad &\tau_u \,(\nabla p + {\bf u} \cdot \nabla {\bf u} - \nu
 \nabla^2 {\bf u} - g \frac{T'}{T_0},
 \nabla q) \\
 +\quad &\tau_u \, (\nabla p + {\bf u} \cdot \nabla {\bf u} - \nu \nabla^2 {\bf u}- g \frac{T'}{T_0},
 \nabla {\bf u} \cdot \nabla {\bf v} + \nu \nabla^2 {\bf v}) \\
 +\quad &\tau_T \, ({\bf u} \cdot T - \nabla \cdot (k \nabla T), \nabla {\bf u} \cdot \nabla
 w + \nabla \cdot (k \nabla w)) \quad \}.
\end{align*}


\documentclass{amsproc}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage[cmtip,all]{xy}

\copyrightinfo{2016}{Todd D. Vance}

\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}

\theoremstyle{definition}
\newtheorem{definition}[theorem]{Definition}
\newtheorem{example}[theorem]{Example}
\newtheorem{xca}[theorem]{Exercise}

\theoremstyle{remark}
\newtheorem{remark}[theorem]{Remark}

\numberwithin{equation}{section}

\begin{document}
\title{A Geometric Algebra Primer}
\author[T. D. Vance]{Todd D. Vance}
%\address{15 Lilac Dr \\ Moorefield, WV 26836}
%\email{tdvance@gmail.com}
\date{\today}

\begin{abstract}
  A brief introduction to Geometric Algebra with an emphasis on algorithms.
\end{abstract}

\maketitle{}

\newcommand{\term}[1]{\emph{#1}}

\newcommand{\ga}{\ensuremath{\mathop{\mathrm{GA}}}}

\section{definitions}

\begin{definition}[Geometric Algebra]
  The \term{geometric algebra} $\ga(n)$ of \term{ambient rank} $n$ is
  the quotient algebra $\mathbf{R}\{[1], [2], \dots, [n]\}/I$, where
  $\mathbf{R}\{[1], [2], \dots, [n]\}$ is the free (unital,
  associative, noncommutative) algebra over the real field
  $\mathbf{R}$ generated by noncommuting elements $[1], [2], \dots,
  [n]$, and $I$ is the (two-sided) ideal of $\mathbf{R}\{[1], [2],
  \dots, [n]\}$ generated by the set of elements of the form $[i][i] -
  1$ and of the form $[i][j] - [j][i]$ when $i\ne{j}$.
\end{definition}

The multiplication operator in $\ga(n)$ is called the \term{geometric
  product} and is written by juxtaposition: $ab$ is the product of $a$
and $b$, in that order.  An (equivalence class of the) element of
$\ga(n)$ of the form $[i_1][i_2]\cdots[i_m]$ is abbreviated
$[i_1i_2\cdots{i}_m]$ and is called a \term{basis blade}.  As a
special case, the empty basis blade $[]$ is defined to be the
multiplicative identity $1$.

\begin{example}
A commonly-used geometric algebra in graphics applications is $\ga[3]$
of ambient rank $3$.  The algebra is generated by the elements $[1]$,
$[2]$, and $[3]$.  Clearly $[1][1] = [] = 1$, $[1][2]=-[2][1]$, and so
on.  From this one finds that $\ga(3)$ is an eight-dimensional vector
space with basis $\{[], [1], [2], [3], [12], [13], [23], [123]\}$.  A
typical element of $\ga(3)$ is then equal to $s[] + a[1] + b[2] + c[3]
+ A[23] + B[13] + C[12] + S[123]$ where $s, a, b, c, A, B, C,$ and $S$
are real numbers.

We consider elements of $\ga(3)$ of the form $a[1]+b[2]+c[3]$ to be
vectors (or rank one elements) and this three-dimensional vector space
is the geometric entity $\ga(3)$ models.  Elements of the form $s[]$,
also just written $s$, are scalars (or rank zero elements), so in a
geometric algebra, one can add a scalar to a vector.  Elements of the
form $A[23] + B[13] + C[12]$ are bivectors (rank two elements), which
model oriented plane regions with an area magnitude.

Just as a vector has direction and magnitude, and one considers two
vectors having the same direction and magnitude to be equal even if
they have different locations in three-space, a bivector has a
containing plane, one of two orientations on that plane, and an area,
so two planar regions having the same area, contained in parallel or
equal planes, and given the same orientation (which may be thought of
as clockwise versus counterclockwise) are considered to be the same
bivector.

Elements of the form $S[123]$ are considered volume elements (rank
three elements), also called pseudoscalars because they have one
degree of freedom in three-dimensional space.  A volume element only
has magnitude and orientation (positive or negative, which may be
thought of as being a right-handed or left-handed coordinate system).

Addition of two elements expressed in the linear combination form
mentioned above is done by combining like terms.  If $x = 4 + 3[1] +
4[2] + 5[12]$ and $y = 3 + 2[1] + 3[2] + 4[12]$, then
$x+y = 7 +5[1] +7[2] + 9[12]$.

Multiplication works like polynomial multiplication, except without
commutativity, and using the rules of converting products of blades
into the standard ones $[]=1$, $[1]$, $[2]$, $[12]$, $[3]$, $[13]$,
$[23]$, and $[123]$.  So, using the same $x$ and $y$ as above, to find
$xy$, one multiplies every term of $x$ by every term of $y$, then
reduces and combines like terms:
\begin{alignat*}{4}
  xy &=&&12 + 8[1] + 12[2] +16[12]\\
  && +~ & 9[1] + 6[1][1] + 9[1][2] + 12[1][12]\\
  && +~ & 12[2] + 8[2][1] + 12[2][2] + 16[2][12]\\
  && +~ & 15[12] + 10[12][1] + 15[12][2] + 20[12][12]\\
  &=&&12 + 8[1] + 12[2] + 16[12]\\
  && +~ &9[1] + 6 + 9[12] + 12[2]\\
  && +~ & 12[2] - 8[12] + 12 - 16[1]\\
  && +~ & 15[12] - 10[2] + 15[1] - 20\\
  &=&& 10 + 16[1] + 26[2] + 32[12]
\end{alignat*}
\end{example}

\subsection{Standard Basis Blades}

Generalizing from the example, we see that swapping adjacent unequal
indices of a basis blade changes its sign and deleting pairs of
adjacent, equal indices does not change the element.  Thus, all basis
blades in $\ga(n)$ are either plus or minus a \term{standard} basis
blade $[i_1i_2\cdots{i}_m]$ ($m \le n$) in which the indices are in
increasing order and there are no duplicate indices.  In this case,
the \term{rank} of the basis blade is $m$.  Any element of $\ga(n)$
can be written uniquely (up to ordering of terms) as a linear
combination of standard basis blades (including $[]$, the rank-zero
empty basis blade equal to $1$ in the algebra), and the rank of that
element is the maximum rank among the basis blades in the linear
combination.  The rank of the $0$ element is defined to be $-\infty$.
Thus, $\ga(n)$ is an algebra filtered by rank.

A nonzero element of $\ga(n)$ that is a linear combination of standard
basis blades of the same rank $r$ is said to be \term{purely} of rank
$r$.  Rank 0 elements (that is, pure rank 0 elements along with the 0
element) are called \term{scalars}.  Pure rank 1 elements (along with
0) are called \term{vectors}.  Pure rank two elements (along with 0)
are called \term{bivectors}, and so on.  All elements are called
\term{multivectors}. When the ambient rank is $n$, rank $n$ elements
(along with 0) are called \term{pseudoscalars}, rank $n-1$ elements
(along with 0) are called \term{pseudovectors}, and so on.

The algebra $\ga(n)$ is generated, as a vector space, by the standard
basis blades $[]$, $[1]$, $[2]$, $\dots$, $[n]$, $[12]$, $\dots$
$[123\dots{n}]$, of which there are $2^n$, so as a real vector
space, $\ga(n)$ has dimension $2^n$.

In addition to the geometric product, other products are defined in
$\ga(n)$.  The \term{inner product} is the symmetric component of the
geometric product: $a\cdot{b} = \frac{ab+ba}{2}$.  The \term{outer
  product} is the antisymmetric component of the geometric product:
$a\wedge{b}=\frac{ab-ba}{2}$.  As the names imply,
$a\cdot{b}=b\cdot{a}$, and $a\wedge{b} = -b\wedge{a}$.  Then, $ab =
a\cdot{b} + a\wedge{b}$.

\subsection{Additional Operations}

Note that for vectors, $a\cdot{b}$ is exactly the standard dot
product, using $\{[1], [2], \dots, [n]\}$ as the standard ordered
basis.  For vectors in $\ga(3)$, the wedge product has the same
magnitude as the cross product, but is a bivector (pseudovector)
rather than a vector.  Also, the wedge product is defined in any
number of dimensions, not just three, and for non-vector elements as
well.

The \emph{standard pseudoscalar} $I$ of $\ga(n)$ is defined to be the
rank-$n$ standard basis blade $[123\dots{n}]$.  Then, $I^2 = II$ must
either be $-1$ or $1$, so $I^4=1$ regardless of $n$.  In particular,
the subalgebra of $\ga(2)$ generated by $[]$ and $I$ is isomorphic to
the complex number field.  In fact $I^2=-1$ in $\ga(2)$ and the
isomorphism maps $1$ to $[]$ and $\imath$ to $I$.  In addition,
$\ga(3)$ contains a subalgebra isomorphic to the quanternion algebra.
This subalgebra is generated by $[]$, $i=[23]$, $j=[13]$, and
$k=[12]$, with $[]$ maping to 1 and $i$, $j$, and $k$ mapping to the
same-named elements of the quaternion ring.

The \term{norm} $|a|$ of an element $a\in\ga(n)$ is defined to be the
square root of the sum of the squares of the coefficients of the
standard basis blades making up the linear combination.  Note for
vectors this reduces to the usual norm for vectors.

The \term{reversion} $\tilde{a}$ of an element $a\in \ga(n)$ is formed
from $a$ by taking the linear combination of standard basis blades
composing $a$, and then reversing the order of multiplication of the
algebra generators in each term: $[i_{j_1}][i_{j_2}]\cdots[i_{j_m}]$
$\rightarrow$ $[i_{j_m}][i_{j_{m-1}}]\cdots[i_{j_1}]$.  Equivalently,
each term of $a$ of pure rank $r$, where $r$ is congruent to $2 $ or
$3$ modulo $4$, is negated.

The \term{grade projection} $\mathrm{proj}_k(a)$ of an element $a\in \ga(n)$ is
formed from $a$ by deleting all terms of pure rank not equal to $k$.

The \term{left inverse} of $a\in \ga(n)$ is an element $b$ satisfying
$ba=1=[]$ and the \term{right inverse} $c$ likewise satisfies $ac=1$.
We use $a^{-1}$ to represent an element that is both the left and right
inverse of $a$.  If $a{\tilde{a}}$ is a nonzero scalar, then
$\frac{a}{a{\tilde{a}}}$ is well-defined by dividing each coefficient of
$a$ by the scalar denominator.  In such a case, $a$ does have a
two-sided inverse and $a^{-1} = \frac{a}{a{\tilde{a}}}$.

The \term{dual} of an element $a$ of $\ga(n)$ is $aI^{-1}$.  Note that
$I^{-1}$ exists and is equal to $I^3$, which is either $I$ or $-I$.
Note that the dual of a scalar is a psuedoscalar, the dual of a vector
is a pseudovector, and so on.  The double dual of $a$ is either $a$ or
$-a$.

Note that in $\ga(3)$, $a\wedge{b}I^{-1}$ is a vector, and is equal to
the vector space cross product $a\times{b}$.  Thus, we define a
\term{generalized cross product} on any $\ga(n)$ to be
$a\times{b}=a\wedge{b}I^{-1}$, the dual of the wedge product.  In
dimensions other than 3, the cross product of vectors is no longer a
vector.  However, in $n$ dimensions, one can take the dual of the
wedge product of $n-1$ vectors to give a vector which geometrically is
similar to the cross product in three dimensions.

The \term{exponential} of $a\in{\ga}(n)$ is computed as follows.  If
$a=0$, $e^0=1$ by definition.  Otherwise, let $\theta=|a|$ and
$b=a/\theta$.  Then use DeMoivre's formula with $b$ taking the role of
the imaginary unit: $e^a = \cos\theta + b\sin\theta$.  The inverse of
this operation, a geometric algebraic logarithm, is difficult and
multivalued, even more so than with complex numbers.

The main use for the exponential is in computing a \term{rotor}.  If
$v$ and $w$ are linearly-independent unit vectors (that is,
$|v|=|w|=1$) in the $n$-dimensional vector space whose basis is the
rank-one standard blades, then $vw$ is a bivector that represents an
oriented plane in the $n$-dimensional space.  A rotation about the
origin in the direction from $v$ to $w$ along an angle $theta$ is then
modeled by the \term{rotor} $r$ in $\ga(n)$ that is $r =
e^{\frac12vw\theta}$.  Then if $a$ is any element (vector or
otherwise) of $\ga(n)$, its rotation is then $ra{\tilde{r}}$.  If $a$
is a vector, so is $ra{\tilde{r}}$, and this is an ordinary vector
rotation.  If $a$ is a bivector representing an oriented plane,
$ra{\tilde{r}}$ is the rotation of the plane.  And so on.

The \term{meet} of two elements $a$ and $b$ in $\ga(n)$ is defined by
$aI^{-1}b$, or the product of the dual of $a$ with $b$.

\section{Algorithms}
\newcommand{\n}{\ensuremath{\mathop{\mathrm{N}}}} An apparent way to
represent a standard basis blade $a=[i_1i_2\dots{i}_m]$ is via the
integer $\n(a)$ defined to be $\sum_{k=1}^{m}2^{i_k}$.  Then, the
product $ab$ of $a=[i_1i_2\dots{i}_m]$ and $b=[j_1j_2\dots{j}_r]$
can be computed as follows:

\begin{enumerate}
\item If $m=0$, let $c$ be the multivector $b$ and return $c$
\item If $r=0$, let $c$ be the multivector $a$ and return $c$
\item Let $c$ be the blade for which $\n(c)$ is the bitwise exclusive
  or of $\n(a)$ and $\n(b)$.
\item Let $s$ be 1.
\item Let $p$ be the maximum of $\n(a)$ and $\n(b)$.
\item Let $d$ be $m$
\item Let $e$ be $1$
\item while $e\le{p}$, do the following:
  \begin{enumerate}
  \item Compute the bitwise and of $e$ and $\n(a)$.
  \item If the result of the bitwise and is nonzero, then replace $d$ with $d-1$.
  \item If $d$ is odd, Compute the bitwise and of $e$ and $\n(b)$.
  \item If $d$ is odd and the result of the bitwise and is nonzero
    then replace $s$ with $-s$.
  \item Replace $e$ with $2e$.
  \end{enumerate}
\item Let $c$ be the multivector that is the real coefficient $s$
  multiplied by the blade given by $c$, and return $c$.
\end{enumerate}

A standard basis blade is simply a nonnegative integer in this
representation.  A choice needs to be made to represent a multivector,
a real linear combination of these blades.

The \term{dense} representation of a multivector in $\ga(n)$ is an
array $A$ of dimension $2^n$, thus having elements $A_0$, $A_1$, and
so on up to $A_{2^n-1}$.  Then, a multivector $\sum_{i=1}^{l}c_ib_i$,
where the $c_i$ are real numbrers and the $b_i$ are standard basis
blades in $\ga(n)$, is represented by the array $A$ in which for
$1\le{i}\le{l}$, $A_{\n(b_i)} = c_i$, and all other elements of $A$
are zero.

The dense representation requires little computation, but uses
$O(2^n)$ memory per element of $\ga(n)$, so it is useful for low
dimensionality, such as in representing the commonly-used $\ga(3)$.

For larger dimensions, a \term{sparse} representation is needed.  Let
$D$ be a \term{dictionary}, algorithmically represented by a hash
table in most cases, but mathematically works like the array: for any
nonnegative integer $i$, $D_i$ is a real number.  For most $i$, this
real number is zero and thus $i$ has no entry in the hash table.  Only
when $D_i$ is nonzero is there an entry in the hash table with key $i$
and value $D_i$.

Then, a multivector $\sum_{i=1}^{l}c_ib_i$, where the $c_i$ are real
numbrers and the $b_i$ are standard basis blades in $\ga(n)$, is
represented by the dictionary $D$ in which for $1\le{i}\le{l}$,
$D_{\n(b_i)} = c_i$, and no other entries are present in $D$ (so that
the dictionary returns the default value of 0 for those).

The sparse representation requires a small amount of computation for
hashing and, sometimes, rebuilding the table, but only requires $O(l)$
memory for an element of $\ga(n)$ having $l$ nonzero terms.  Thus, the
sparse representation is most useful for large $n$ when many elements
are such that most standard basis blades have a zero coefficient.

In both cases, the addition procedure is evident and involves adding
the values from one array or dictionary to the same-indexed values of
the other.

The geometric product, however, requires an all-to-all mapping of
array or dictionary elements.  We illustrate the algorithm for the
array case, with the dictionary case being nearly identical, just
iterating over keys in the hash table instead of over all integers in
the range from $0$ to $2^{n-1}$.

Suppose $A$ and $B$ are arrays representing multivectors in $\ga(n)$.
We compute a new array $C$ with $2^n$ entries representing the
geometric product of the multivectors $A$ and $B$.

\begin{enumerate}
\item Initialize $C$ to $C_0=C_1=\cdots=c_{2^{n-1}}=0$.
\item For each $i$ from 0 to $2^{n-1}$ such that the coefficient $A_i$
  is nonzero
  \begin{enumerate}
  \item For each $j$ from 0 to $2^{n-1}$ such that the coefficient
    $B_j$ is nonzero
    \begin{enumerate}
      \item Let $k$ be the integer that is the result of multiplying
        together the blades represented by $i$ and $j$, and let $s$ be
        the coefficient, $1$ or $-1$, of the result.
      \item Let $C_k$ be $C_k + A_iB_js$, an ordinary sum and product
        of real numbers.
    \end{enumerate}
  \end{enumerate}
  \item Return the multivector $C$.
\end{enumerate}

\bibliographystyle{amsplain}

\end{document}