\chapter{Augmenting a Term Rewriting System through Synthesis}
\label{chapter:synthesis}

Although a Halide-expression term rewriting system is necessarily incomplete, we can strengthen
it by finding expressions on which the TRS can no longer make progress and creating
rules that will rewrite them further.
In this section, we describe a workflow for automatically augmenting the Halide simplifier TRS with new rules. We evaluate the usefulness of our process by comparing synthesized rules to those written by human programmers; describing some uses of the process by Halide developers; and carrying out a large-scale experiment in synthesizing rules for the simplifier in bulk, which resulted in new rules being merged into the Halide compiler.

\section{Synthesizing rewrite rules}
\label{sec:synthsimplifierrules}

\begin{figure*}
%\includegraphics[width=1.\columnwidth,natwidth=610,natheight=642]{figures/synthesis-flow.pdf}
%\includegraphics[width=1.\columnwidth]{figures/synthesis-flow.pdf}

% x_1 < select(x_2, c_0, c_1) + x_1 -> !x_2

  \tikzstyle{stage}=[fill=blue!10, draw=none, minimum height=3em, minimum width=11em]
  \tikzstyle{example}=[fill=orange!10, draw=none, minimum height=3em, minimum width=23em]
  \tikzstyle{label}=[fill=blue!10, draw=none, minimum height=3em, minimum width=1em]
  \begin{tikzpicture}[node distance=1.5cm,auto,>=latex']
    \node (s1) [stage] {\shortstack{Input expression}};
    \node (s2) [stage] [below of=s1] {\shortstack{Generated LHS\\patterns (Fig.~\ref{fig:lhspatterns})}};
    \node (s3) [stage] [below of=s2] {\shortstack{AC matching\\(Sec.~\ref{sec:rhsacmatching})}};
    \node (s4) [stage] [below of=s3] {\shortstack{Superoptimized with\\CEGIS (Sec.~\ref{sec:rhssynthesis})}};
    \node (s5) [stage] [below of=s4] {\shortstack{With symbolic\\constants (Sec.~\ref{sec:generalizing-constants})}};
    \node (s6) [stage] [below of=s5] {\shortstack{Substitute concrete\\values of $x_i$}};
    \node (s7) [stage] [below of=s6] {Candidate predicate};
    \node (s8) [stage] [below of=s7] {\shortstack{Verify or find new\\counterexample}};
    \node (s9) [stage] [below of=s8] {Rule with predicate};
    \node (s10) [stage] [below of=s9] {Add variants (Sec.~\ref{sec:filtering})};
    \node (l1) [label] [left of=s1,node distance=6em] {(a)};
    \node (l2) [label] [left of=s2,node distance=6em] {(b)};
    \node (l3) [label] [left of=s3,node distance=6em] {(c)};
    \node (l4) [label] [left of=s4,node distance=6em] {(d)};
    \node (l5) [label] [left of=s5,node distance=6em] {(e)};
    \node (l6) [label] [left of=s6,node distance=6em] {(f)};
    \node (l7) [label] [left of=s7,node distance=6em] {(g)};
    \node (l8) [label] [left of=s8,node distance=6em] {(h)};
    \node (l9) [label] [left of=s9,node distance=6em] {(i)};
    \node (l10) [label] [left of=s10,node distance=6em] {(j)};

    \draw [line join=miter] (l8.west) -- ([xshift=-1em] l8.west) -- ([xshift=-1em] l6.west) -- ([xshift=-0.9em] l6.west) node {};
    \path[->] ([xshift=-1em] l6.west) edge node {} (l6.west);

    \path[->] (s1) edge node {} (s2);
    \path[->] (s2) edge node {} (s3);
    \path[->] (s3) edge node {} (s4);
    \path[->] (s4) edge node {} (s5);
    \path[->] (s5) edge node {} (s6);
    \path[->] (s6) edge node {} (s7);
    \path[->] (s7) edge node {} (s8);
    \path[->] (s8) edge node {} (s9);
    \path[->] (s9) edge node {} (s10);

    \node (e1) [example] [right of=s1,node distance=19em]
          {$(y + 2) < \hsel(u < z, -3, 4) + (y + 2)$};
    \node (e2) [example] [right of=s2,node distance=19em]
          {\shortstack{
              \color{darkgray}
              \tiny{$\ldots$} \\
              \color{darkgray}
              \tiny{$(x_1 + 2) < x_2 + (x_1 + 2)$} \\
              $x_1 < \hsel(x_2, -3, 4) + x_1$ \\
              \color{darkgray}
              \tiny{$\hsel(x_1 < x_2, -3, 4)$} \\
              \color{darkgray}
              \tiny{$\ldots$}}};
    \node (e3) [example] [right of=s3,node distance=19em]
          {\shortstack{No reassociated/commuted variants \\ match an existing rule.}};
    \node (e4) [example] [right of=s4,node distance=19em]
          {$x_1 < \hsel(x_2, -3, 4) + x_1 \rightarrow \boxed{\neg x_2}$};
    \node (e5) [example] [right of=s5,node distance=19em]
          {$x_1 < \hsel(x_2, c_0, c_1) + x_1 \rewrites \neg x_2$};
    \node (e6) [example] [right of=s6,node distance=19em]
          {\shortstack{
              $0 < \hsel(\textit{false}, c_0, c_1) + 0 = \neg \textit{false} ~ \wedge$ \\
              $1 < \hsel(\textit{false}, c_0, c_1) + 1 = \neg \textit{false} ~ \wedge$ \\
              $0 < \hsel(true, c_0, c_1) + 0 = \neg true$
          }};
    \node (e7) [example] [right of=s7,node distance=19em]
        {$0 < c_1 \wedge c_0 \le 0 $};
    \node (e8) [example] [right of=s8,node distance=19em]
        {\shortstack{
            $\exists~ x_1, x_2, c_0, c_1 \;.\; (0 < c_1 \wedge c_0 \le 0) ~\wedge$ \\
            $(x_1 < \hsel(x_2, c_0, c_1) + x_1 \neq \neg x_2)$ ? \\
            No solutions. Predicate is sufficient.
        }};
    \node (e9) [example] [right of=s9,node distance=19em]
          {$x_1 < \hsel(x_2, c_0, c_1) + x_1 \rewrites \neg x_2 \pred 0 < c_1 \wedge c_0 \le 0 $};
    \node (e10) [example] [right of=s10,node distance=19em]
          {\shortstack{
              $x_1 < \hsel(x_2, c_0, c_1) + x_1 \rewrites \neg x_2 \pred 0 < c_1 \wedge c_0 \le 0 $ \\
              $x_1 < x_1 + \hsel(x_2, c_0, c_1) \rewrites \neg x_2 \pred 0 < c_1 \wedge c_0 \le 0 $
          }};

    \path[->] (e1) edge node {} (e2);
    \path[->] (e2) edge node {} (e3);
    \path[->] (e3) edge node {} (e4);
    \path[->] (e4) edge node {} (e5);
    \path[->] (e5) edge node {} (e6);
    \path[->] (e6) edge node {} (e7);
    \path[->] (e7) edge node {} (e8);
    \path[->] (e8) edge node {} (e9);
    \path[->] (e9) edge node {} (e10);

  \end{tikzpicture}
  \caption{Overall flow of the synthesis pipeline (in blue) with worked example (in orange). (a) We harvest expressions from real compilations on which the TRS could make no further progress. (b) We enumerate all subtrees of these to generate left-hand sides that would match each expression. Our example will focus on one such pattern. (c) We obtain a right-hand side by first checking if any reassociated or commuted variants of it match an existing TRS rule. (d) If not, we superoptimize the pattern using CEGIS. (e) This rule is specific to the particular values of any constants that appear. We then replace any constants with new variables $c_0, c_1, etc.$, to obtain a more general version of the rule. We must now synthesize a sufficient condition on these new variables under which the rule still holds. (f) To do this, we treat the rewrite as an equality and take the conjunction over a set $S$ of different values for the non-constant variables $x_0, x_1, etc.$ (g) Simplifying the result gives a candidate predicate. This is a \emph{necessary} condition. (h) We then check if it is also \emph{sufficient} condition using Z3. (i) If a counterexample is found, we add these new values of $x$ to $S$ to obtain a new candidate predicate and repeat until we have a sufficient condition to serve as our predicate. (j) Finally, we construct variants of the rule in which the LHS has been commuted.}
\label{fig:synthesis-flow}
\end{figure*}

Given an \emph{input expression} that the TRS failed to simplify, our goal is to find a rule that
can rewrite it. A high-level view of the synthesis pipeline is shown in Figure~\ref{fig:synthesis-flow}.
At a high level, we begin with an expression we would like to be able to further simplify, and use it to choose patterns to act as candidate LHSs for new rules. We then attempt to synthesize RHSs that match those candidates LHSs
%and Algorithm~\ref{alg:synthesis-algorithm} shows the corresponding pseudocode.
We begin with an expression we will attempt to further simplify;
first, we synthesize rules that contain concrete constants from the input expression.
Next we generalize those rules by replacing constant values with symbolic constants and synthesizing compile-time
predicate guards
that check the validity of the rule on the values matched by the symbolic constants. If we
find such a rule, we know that adding it to the TRS will enable it to simplify the input
expression as well as any similar expressions it may encounter.

\subsection{Generating LHS Patterns}

Useful input expressions may come from a bug report, or may be gathered from compiler logs. With logging enabled, the compiler records two
kinds of problematic expression for which new simplifier rules may be helpful:
non-monotonic expressions, which can result in over-conservative
bounds for loops and memory allocations; and proof failures,
which may prevent Halide from performing certain optimizations
(see Section~\ref{sec:uses-of-trs}).
Of course, absent an oracle, it is difficult to know if the TRS has fully simplified
some expression or if it lacks the solving power to continue simplification.
When the simplifier is used as a proof engine, its goal is to reduce an expression to true.
In this case, we can fuzz-test failed proofs by assigning all variables in an expression
random values and evaluating; if we cannot find an assignment that evaluates to false,
the expression may indeed be reducible to true, so we log it as an input expression.

  Our first step is to find LHS terms that could match the input expression, or any portion of it.
We can enumerate all such terms through a kind of inverse matching.
When we rewrite an expression with a rule,
we match the expression to the rule's LHS by finding a substitution for all variables in
the LHS that will unify it with the input expression. Here, we start with an input expression,
then fix a substitution by mapping some of its subterms to fresh variables. We
replace those subterms with the new variables, constructing a term that can
be matched with the input term.
If we perform this inverse matching for all sets of subterms, we find \emph{all possible LHSs} that could match the
input expression.
When a subterm occurs more than once in the input expression, we construct a LHS that
uses the same variable to replace it in multiple places and LHSs that replace its
occurrences with different variables.
We repeat the procedure on all \emph{subterms} of the input expression.  The result is the set of all
LHSs that match any part of the input expression. See Figure~\ref{fig:lhspatterns} for a worked example.

\begin{figure*}
\begin{tabular}{lll}
\begin{tikzpicture}[level distance=12mm,baseline=(current bounding box.center)]
\tikzstyle{level 1}=[sibling distance=15mm]
\tikzstyle{level 2}=[sibling distance=8mm]
\tikzstyle{level 3}=[level distance=10mm,sibling distance=5mm]

% tried to label subtrees but positioning looks weird, fix later
\node (+) {+}
  child { node (+2) {+}
    child { node (z) {z}  } % edge from parent node[left,draw=none] {$v_1$}
    child { node (2) {2} }}
  child { node (min) {\hmin}
    child { node (x) {x}}
    child { node (-) {-} %edge from parent node[right,draw=none] {$v_2$}
      child {node (y) {y}}
      child {node (z1) {z} } % edge from parent node[right,draw=none] {$v_3$}}
    }};

\begin{pgfonlayer}{background}
\fill[red,opacity=0.3] \convexpath{x, min, z1, y}{10pt};
\fill[blue,opacity=0.3] \convexpath{y, -, z1}{10pt};
\fill[green,opacity=0.3] \convexpath{z, +2, 2}{10pt};
\end{pgfonlayer}
\end{tikzpicture} &
\begin{tabular}{llll}
$(z + 2) + \hmin(x, y - z)$ & $\hmin(x, y - z)$ & $z + 2$ & $y - z$ \\
$v_1 + \hmin(x, y - z)$ & $\hmin(x, v_2)$ & & \\
$v_1 + \hmin(x, v_3)$ & & & \\
$(z + 2) + \hmin(x, v_3)$ & & & \\
$v_1 + v_2$ & & &
\end{tabular}
\end{tabular}
\caption{Given the input expression $(z + 2) + \hmin(x, y - z)$, we find all possible
LHS patterns by substituting fresh variables for subterms, for all valid combinations. Then, we repeat the process for
each individual subterm. This process yields the list of candidate LHS terms on the right.}
\label{fig:lhspatterns}
\end{figure*}

This number of LHSs is exponential in the size of the input expression, so we use a few heuristics to narrow
our search. We bound the size of candidate LHSs to have seven or fewer leaves, since longer terms are less likely to
result in rules general enough to justify inclusion in the ruleset.
Additionally, since we process input expressions in batches, we remove
duplicate LHSs as well as LHSs that differ only in the values of their constants.
Finally, we have found it helpful to keep a blacklist of LHSs for which we previously
failed synthesize rules; for example, $v_1 + v_3$
cannot form a rule, so we filter it out as a candidate.

\subsection{Synthesizing Right-Hand Sides}
\label{sec:synthesizing-candidate-rules}
%
Given a candidate left-hand side, we attempt to
synthesize a right-hand side that is semantically equivalent and
respects the simplifier reduction order, such that $\mathit{LHS} > \mathit{RHS}$.
We employ two strategies for synthesizing right-hand sides:
delayed AC matching, and counter-example guided inductive synthesis (CEGIS) of
the RHS followed by synthesis of the rule predicate guard.

\subsubsection{Finding Right-Hand Sides through AC Matching}
\label{sec:rhsacmatching}
The first strategy reflects the Halide design decision not to perform any AC matching in the TRS, for efficiency reasons.
Instead, AC matching can effectively performed through adding additional rules. It is possible that our candidate LHS, which currently cannot be rewritten by the simplifier rules, could be matched by an existing rule after a suitable application of associativity and commutativity laws to the LHS.
To this end, we generate all possible reassociations and commutations of the candidate LHS term and pass them to the existing TRS.
If any of them can be simplified, we create a new rule that rewrites
the original, untransformed LHS term to the result of the simplification.  Note that this result may include applications of more than one rewriting step, so the new rule is not merely an AC-variant of an existing rule.

For example, assume our TRS includes the rule $(x + y) - x \rewrites y$,
and let $((u + 2) + v) - u$ be a candidate LHS term. The rule does not match the candidate but it matches its variant $(u + (v + 2)) - u$, rewriting it to the result $v + 2$. The candidate and the result give us the rule $((u + 2) + v) - u \rewrites v + 2$.

We can consider this procedure a kind of lazy offline AC matching, because if the Halide TRS
performed full AC matching while rewriting expressions, it would be able to apply the rule $(x + y) - x \rewrites  y$ to the candidate expression $((u + 2) + v) - u$ after reassociating it to $(u + (v + 2)) - u$, obtaining the result $v + 2$.  Delaying AC matching to synthesis has the effect of restricting the system to a single, offline round of AC and memoizing the result in the form of a new TRS rule if we are successful.
Note that the synthesis procedure below could have found this rule, but checking for AC
variants of existing rules is far cheaper. About three-quarters of our synthesized rules are generated by this method.

\subsubsection{Finding Right-Hand Sides through CEGIS}
\label{sec:rhssynthesis}
If the first method fails, we apply counterexample guided inductive synthesis (CEGIS)~\citep{DBLP:conf/aplas/Solar-Lezama09} to superoptimize the left-hand side pattern.
In superoptimization~\citep{massalin1987superoptimizer}, we take a program and search
for an equivalent program within some grammar that is preferable according
to some cost function. Here our grammar is that of the Halide expression language,
the method for testing program equivalence is the Z3 solver, and we use the node
count of the programs as a proxy for our full reduction order. \newpage

Similar to prior work in superoptimization~\citep{regehr2018superoptimization, mangpo2016superoptimization},
we search the expression space for an equivalent RHS using a CEGIS loop. This loop alternately calls Z3 as a
verifier, which checks if a candidate RHS is equivalent to the LHS on all inputs,
and a learner, which finds a candidate RHS that is equivalent to the LHS on
a limited set of inputs.
We begin by choosing a single-op
RHS and ask the verifier if it is equivalent to the LHS. If it is not, we get back
a counterexample of assignments to the variables for which the right- and left-hand side are
not equivalent, which we keep as a set of test inputs.
We then ask the learner for a new RHS that is equivalent to the LHS
only on the counterexample assignments we found in the last step.
If we cannot find an equivalent single-op sequence,
we iteratively increase the number of operations, ensuring we find shorter sequences
first.  If CEGIS returns a sequence semantically equivalent to the LHS pattern with fewer
operations, we use it together with our LHS to form a candidate rule.

 The learner portion of the CEGIS loop creates a candidate RHS
  %expression from a parameterized bytecode
  %sequence of fixed size that is fed to an interpreter. Each bytecode
  %instruction takes parameters that select between the possible operators and
  %operands available to it. Thus,
  %this bytecode
  %sequence serves as an SSA representation of an expression tree. The
  %interpreter is evaluated abstractly on symbolic inputs to produce a
  %sketch~\citep{DBLP:conf/aplas/Solar-Lezama09, torlak2014lightweight},
  %capable of acting as any Halide expression in our
  %search space depending on the bytecode values. The learner uses Z3
  by creating a sketch~\citep{DBLP:conf/aplas/Solar-Lezama09, torlak2014lightweight}
  that consists of a small bytecode interpreter that encodes the possible
  operations and operands the RHS can use, along with a bound on the number of instructions.
  The learner uses Z3 to query for a sequence of bytecodes within the bound, that, when
  run through the interpreter, is semantically
  %solve for the bytecode values that makes the sketch semantically
  equivalent to the LHS over the test inputs. If a solution is found,
  substituting the produced bytecode values into the sketch
  and applying the TRS reduces it to a concrete candidate RHS. One
  complication arising from this approach is that a bytecode sequence
  of a fixed number of ops may produce expression trees of a larger
  size if intermediate values are reused. We reject any such solutions
  in a post-pass by checking each synthesized RHS against the LHS
  using the full reduction order. An alternative solution would be
  introducing let bindings into our search space so that the size of
  the expression tree could be bounded by the number of ops in its SSA
  form. However, we could not identify any significant rewrite rules
  lost to this filtering, so we deemed this an unnecessary
  complication.

While Z3 is a powerful tool for synthesis, there are certain types of expressions
containing division or modulo that Z3 nearly always fails to reason about during the CEGIS process. (We experimented with the SMT solvers Yices2~\citep{jovanovic2017solving} and MathSAT5~\citep{mathsat5}, but were not able to obtain appreciably better results.)
Z3 is better able to reason about expressions containing concrete constants, rather than
universally quantified variables, so we synthesize rules using candidate LHSs with
concrete constants from the input expression and generalize them later.
We limit the use of division and modulo in our op-codes to be division
or modulo by 2 only, and rely on the generalization step described next to
widen the set of denominators for which a rule applies.  Because of this
restriction, our synthesized rules cannot contain non-constants in denominators
or the right-hand side of a modulo.  As a result, our synthesis system cannot
construct all rules a human can.

\begin{table*}
\caption{Sample rules synthesized by our process. }
\small
\begin{tabular}{l|l|l}
LHS & RHS & Predicate \\
\hline
$(x*y) - (z + (w*x))$ & $(x*(y - w)) - z $ & \\
$x < (y + x) + z$ &  $0 < (y + z)$ & \\
$\hmax(x*x, y) + \hmax(z, w*w) < c_0$ & false & $c_0 <= 0$ \\
$\hsel(x, c_0, y) < \hmin(\hsel(x, c_1, y), c_2)$ & false & $\hmin(c_1, c_2) <= c_0$ \\
$\hmin((x + ((y - x)/c_0)*c_0) + c_1, y)$ & $y$ & $1 <= c_1 \wedge -1 <= (-1/c_0)*c_0 + c_1$ \\
\end{tabular}
\label{tab:samplerules}
\end{table*}

\subsection{Generalizing Constants and Finding Predicate Guards}
\label{sec:generalizing-constants}

If either AC-matching search (section~\ref{sec:rhsacmatching}) or CEGIS-based synthesis (section~\ref{sec:rhssynthesis}) were successful,
we now have a candidate rewrite
rule that contains concrete values originating from the input expression.
To generalize the rule, we replace such constants with fresh \emph{symbolic constants}
and synthesize a guard that is true when the rule is valid.
Recall that in the Halide TRS, a variable in the LHS matches any subterm, while a
symbolic constant matches only a constant value (see section~\ref{sec:customalgo}); the guards, which are predicates over symbolic constants, can thus be evaluated at compile time.

Our goal is to generalize the equality by synthesizing a guard predicate $\phi$
over the symbolic constants in the LHS and RHS terms such that our rule is valid whenever
$\phi$ evaluates to true:
\[ \forall \vec{c} \forall \vec{x} \;.\; \phi(\vec{c}) \implies LHS(\vec{x},\vec{c}) = RHS(\vec{x},\vec{c})
\]

First, we check to see if this condition is satisfied when $\phi$ is
always true. If it is, then no predicate guard is needed. Otherwise, we need
to synthesize an expression for $\phi$. We find candidates for $\phi$ iteratively
by first choosing a small set of values $S$ for the variables
in $\vec{x}$ and finding the candidate guard $\phi_S$. We check to see if $\phi_S$
is a sufficient predicate guard for all $\vec{x}$; if it is not, we add
counterexamples to the set $S$ and repeat.

\[ \forall \vec{c} \forall \vec{x} \in S \;.\; \phi_S(\vec{c}) \implies LHS(\vec{x},\vec{c}) = RHS(\vec{x},\vec{c})
\]

We initialize $S$ with all basis vectors, which are
values $\vec{x} = ( 0, \ldots, 0, 1, 0, \ldots, 0 )$ that include exactly one unit value,
plus the zero vector.
We then unwind the right-hand side of the implication and substitute in the concrete values
from $S$ to get:

\[ \forall \vec{c} \forall \vec{x} \in S \;.\; \phi_S(\vec{c}) \implies (LHS(\vec{x_1},\vec{c}) = RHS(\vec{x_1},\vec{c}) \wedge \ldots \wedge
LHS(\vec{x_k},\vec{c}) = RHS(\vec{x_k},\vec{c}))
\]

We use the Halide TRS itself to simplify the conjunction on the right-hand side of the
implication. Since all occurrences of $\vec{x}$ have been replaced with concrete
values, we get back an expression that contains only symbolic constants, which we
use as our candidate guard $\phi_S$.

We test whether $\phi_S$ is sound on all $\vec{x}$.
\[ \exists \vec{c} \; \exists \vec{x}
   \;.\; LHS(\vec{x},\vec{c}) \not= RHS(\vec{x},\vec{c})
\]

If this query has a solution $\vec{x}$, then the guard is unsound.
If so, we add the counterexample $\vec{x}$ to $S$, and construct a new guard $\phi_S$.
We repeat this process for several iterations (four, in our experiments) and if
we fail to find a sound guard, we switch to an alternative strategy that converts
the current (unsound) candidate $\phi_S$ to disjunctive normal form and tests
each clause in turn to check if it is a sufficient guard.
If it is, that clause becomes the guard.  If no clause is sound, we discard the rule.
If the loop terminates with Z3 timing out or returning ``unknown'', we return
the current $\phi_S$, flagging it as requiring a manual proof.
We exclude all such cases from our experiments.

As an example, consider the candidate rule:
%
\[ x_0 < \hsel(x_1, c_0, c_1) + x_0 \rewrites \neg x_1
\]
We initialize $S$ with three basis vectors $\{(0,\mathit{false}), (0,\mathit{true}), (1,\mathit{false})\}$ and construct $\phi_S$:
%
\begin{equation*}
\begin{split}
 \phi_S(\vec{c}) \iff
 &  \forall_{\vec{x} \in S} \;.\; LHS(\vec{x},\vec{c}) = RHS(\vec{x},\vec{c}) \\
 \iff &
 0 < \hsel(\mathit{false}, c_0, c_1) + 0 = \neg\mathit{false} \; \wedge \\
                                                   & 0 < \hsel(\mathit{true}, c_0, c_1) + 0 = \neg \mathit{true}  \; \wedge \\
                                                   & 1 < \hsel(\mathit{false}, c_0, c_1) + 1 = \neg\mathit{false}
\end{split}
\end{equation*}

Simplifying the RHS with the TRS, we obtain $\phi_S$:
%
\[  \phi_S(\vec{c}) \iff 0 < c_1 \wedge c_0 \le 0
\]

Next we check whether $\phi_S$ is sound for all $\vec{x}$.  It is, so we have a completed rule:

\[ x_0 < \hsel(x_1, c_0, c_1) + x_0) \rewrites \neg x_1 \;\pred \;0 < c_1 \wedge c_0 \le 0
\]

\subsection{Adding Rule Variants}
\label{sec:rulevariants}
Once we have a generalized rule with a valid predicate, we eagerly compensate for the lack
of AC matching in the Halide TRS by adding AC variants of the rule as well. We find
all commuted variants of the rule's LHS,
with respect to the partial commutative canonicalization as described in Section~\ref{sec:customalgo}.
 (This is exponential in the size of the number
of commutative operators, which is tractable given our bounds on LHS term size).
Then, we find all reassociations of the rule's right-hand side. For each variant LHS,
we choose a RHS variant by serializing expressions to strings and finding the RHS
that has the shortest edit distance from that LHS.

For example, the LHS of the first rule below has four additions and can be commuted
to 16 variants. The RHS of the rule can be reassociated in two different ways. For the
commuted variant of the LHS on the second line, we choose the other means of reassociating
the RHS as it has a smaller edit distance.

\begin{equation*}
\begin{split}
(x + (y - ((z + (w + x)) + u))) & \rewrites y - (z + (w + u))) \\
(y - (((w + x) + z) + u)) + x & \rewrites y - ((z + w) + u)
\end{split}
\end{equation*}

The intuition is that there is no a priori reason
to prefer one reassociated variant to another; they are almost certainly equal in
terms of our reduction order. Thus, we choose the RHS that perturbs the structure of the
LHS as little as possible, in order to avoid rewriting common subexpressions in the hopes
of canceling them out later.

\subsection{Filtering Rule Output}
\label{sec:filtering}
As a final step, we check each output rule for redundancy with the rule batch found
by the synthesis pipeline. For each new rule, we check
that no earlier rule has precisely the same LHS and predicate; if so, it can be discarded.
Then, we check that no earlier rule is more general than the current rule: a rule is more
general than another if they have similar LHSs, but a variable appears in the first rule
in a place where the second rule has a more specific subterm, or if they have the same LHS
but the predicate of the first rule implies the predicate of the second.

Finally, we
check that the candidate rule obeys our reduction order in order to
preserve our termination guarantee. If the candidate rule passes these
filters, and the predicate has not been flagged for human review, the
rule can be added to the TRS ruleset automatically without any human
auditing.

\section{Evaluation of Simplifier TRS Synthesis}
\label{sec:evaluation}

% (1186-367)/1186
\newcommand{\PercentPossibleToSynth}{69\%}
\newcommand{\NumRulesInCorrectnessExperiment}{321}
\newcommand{\PercentRulesResynthesized}{58\%}

In evaluating the benefits of the verifier and synthesizer, we answer the following questions:

\begin{itemize}
  \item \textbf{Does the synthesizer produce better rules than a human expert?} The TRS has been manually extended five times in response to bug reports pointing out limitations of the compiler. We synthesized these five rulesets automatically and found that the human-authored rules were less general and in one case were incorrect. (Section~\ref{sub:bugfixes})

  \item \textbf{What is the best way to use synthesis and verification in development?} We survey several cases from recent Halide development where human experts used the synthesis machinery as an assistant, finding that this hybrid model is more powerful than either the human developer or the synthesizer alone. (Section~\ref{sub:synthassistant})
  \item \textbf{Can synthesis be used for large-scale improvements of the TRS?} We gather a corpus of over 100,000 expressions on which the TRS can make no progress and iteratively synthesize rules using the corpus as input. We synthesize \NumRulesSynthesized  rules and add them to the TRS ruleset without a human audit. We find that the enhanced ruleset reduces peak memory usage in compiled code, sometimes dramatically, in 197 of our benchmarks. We also find no significant compile-time slowdown even with this 4.5-fold increase in ruleset size. (Section~\ref{sub:endtoendexperiment})
  \item \textbf{Could the entire TRS have been synthesized?} Encouraged by the large-scale experiment, we ask how far we are from being able to bootstrap the entire TRS automatically---something that we considered too ambitious originally. First, we find that \PercentPossibleToSynth~of the existing ruleset is accessible to our current synthesizer in principle; the remaining rules contain operators not yet supported by the tool. % or cannot be reasoned about automatically by our solver.
  We test the synthesizer's power by removing \NumRulesInCorrectnessExperiment{} accessible rules from the original ruleset one by one and attempting to synthesize a replacement, successfully finding a replacement rule \PercentRulesResynthesized{} of the time.  We find this encouraging for future applications of the synthesizer. (Section~\ref{sub:replacementexperiment})
\end{itemize}

We discuss these findings in more detail below, grouping them into three sections. First we examine bug reports from Halide’s past and evaluate whether the machinery presented in this paper could have fixed them automatically. Second, we examine cases where beta versions of our verifier and synthesizer assisted humans both in fixing bugs and in correctly making larger changes to the compiler. Third, we fuzz the compiler to mine for issues that could be fixed with new simplifier rules, and automatically fix them before they ever appear as a bug in a real program. In this way we demonstrate that this machinery would have been useful in the past, is useful in the present, and will help avoid entire classes of bugs in the future.

\subsection{Comparing the Synthesizer to Human-Authored Rules}

\subsubsection{Does the Synthesizer Produce Better Rules than a Human Expert?}
\label{sub:bugfixes}

%We expect a human expert to create rules that are as general as possible while also including rules that take advantage of less general situations, such as when special cases allow stronger rewrites.  Can a synthesizer produce rules that are both general and expressive?

%We compared synthesized rules against five sets of rules added manually. We have found that the expert wrote rules that were less general than the synthesized rules, and in some cases were incorrect. Additionally, the synthesizer avoided adding a specialized rule because the TRS could already achieve its effect with rules present in the TRS. We discuss in Section~\ref{sec:limitations} the limitations of when the synthesizer cannot achieve such general rules.

% AA: I found the two paragraphs above redundant with the summary we just gave in the itemized list.

% A) https://github.com/halide/Halide/pull/3719
% B) https://github.com/halide/Halide/pull/3761
% C) https://github.com/halide/Halide/pull/3765
% D) https://github.com/halide/Halide/pull/3770
% E) https://github.com/halide/Halide/pull/3780
% F) https://github.com/halide/Halide/pull/4721
% G) https://github.com/halide/Halide/pull/4772
% H) https://github.com/halide/Halide/pull/4439
% I) https://github.com/halide/Halide/pull/4850

We searched through Halide’s change history and selected the five pull requests that addressed issues by adding new rewrite rules to Halide’s TRS. These pull requests occurred before the Halide developers started routinely using the verifier and synthesizer when changing the TRS, labeled here as $\mathbb{A}$-$\mathbb{E}$. These can be found in their original form as patches on the Halide project website
\footnote{
$\mathbb{A}$: \url{https://github.com/halide/Halide/pull/3719} \\
$\mathbb{B}$: \url{https://github.com/halide/Halide/pull/3761} \\
$\mathbb{C}$: \url{https://github.com/halide/Halide/pull/3765} \\
$\mathbb{D}$: \url{https://github.com/halide/Halide/pull/3770} \\
$\mathbb{E}$: \url{https://github.com/halide/Halide/pull/3780}
}.
Creating these rewrite rules as a human is an amount of work disproportionate to the size of the change. The author of the rules must prove them correct on paper, and a second reviewer must check their work. As we will see, bugs can slip through despite this review.

In each case we take the test expressions committed as part of the change and feed them to our synthesizer to see if it would have produced the same rewrite rules as the humans did. In cases where humans did not check in tests for their new rules, we wrote our own. In total, across these five cases humans added 24 new rules. The synthesizer generated 42, covering all but one of the human rules, while correcting and generalizing others. In cases $\mathbb{A}$, $\mathbb{C}$, and $\mathbb{E}$, the rules generated by the synthesizer are an exact match to the human-generated rules. In case $\mathbb{B}$ the synthesizer matched the human but also crafted 8 commuted variants of the human rules, making them more widely applicable.

As an example, for the human-written rule:

\[
\hmax(\hmax(x, y) + c_0, x) \rewrites \hmax(x, y + c_0) \pred c_0 < 0
\]

The synthesizer produced effectively the same rule, along with a variant:

\begin{align*}
& \hmax((\hmax(x, y) + c_0), x) \rewrites \hmax((y + c_0), x) \pred c_0 \leq 0 \\
& \hmax(x, (\hmax(x, y) + c_0)) \rewrites \hmax(x, (y + c_0)) \pred c_0 \leq 0
\end{align*}

Case $\mathbb{D}$ is the most interesting. It contains four rules involving comparisons of $\hmin$ and $\hmax$ operations. What happened for each was identical, so we will only discuss the $\hmin$ rules. The first rule is:

\[
\hmin(x, c_0) < \hmin(x, c_1) + c_2 \rewrites \hfalse \pred c_0 \geq c_1 + c_2)
\]

This rule is incorrect (consider $c_0 = c_2 = 1$, $x = c_1 = 0$). It can be fixed by adding the term $c_2 \leq 0$ to the predicate. The synthesizer produced the correct version of this rule, along with two generalizations of it:

\begin{align*}
& \hmin(x, c_0) < \hmin(x, c_1) + c_2 \rewrites  \hfalse \pred c_2 \leq 0 \wedge c_1 + c_2 \leq c_0 \\
& \hmin(x, c_0) < \hmin(x, y) + c_1 \rewrites c_0 - c_1 < \hmin(x, y) \pred c_1 \leq 0 \\
& \hmin(x, c_0) < \hmin(y, x) + c_1 \rewrites c_0 - c_1 < \hmin(y, x) \pred c_1 \leq 0
\end{align*}

The second human rule was:
\[
\hmin(x, c_0) < \hmin(x, c_1) \rewrites \hfalse \pred c_0 \geq c_1
\]
The synthesizer found a more general rule, along with three other commuted variants (elided for space):
\[
\hmin(x, y) < \hmin(x, z) \rewrites y < \hmin(x, z)
\]
Any expression which matches the human-written rule would also match the synthesized one. The synthesized version does not simplify to the constant false in a single step. However, after applying this rule to the case considered by the human, we get $c_0 < \hmin(x, c_1)$ where $c_0 \geq c_1$. The simplifier then reduces this to false in a second step, so the human-written rule becomes unnecessary. The synthesizer considered the human-written rule, but discarded it as less general than the one above.

Case $\mathbb{D}$ also included the rewrite rule:
\[
x\; \%\; x \rewrites 0
\]
which was the sole rule the synthesizer could not generate, as we did not include modulo by non-constants in our CEGIS interpreter.

With this one exception, across these five code changes the synthesizer generated more general, more correct rules than the humans, and would clearly have been a useful assistant to the Halide developers if they had had it at the time.

\subsubsection{What Fraction of the Halide Rules Could Have Been Synthesized?}
\label{sub:replacementexperiment}
If the simplifier ruleset had not yet been written by hand, would it have been possible to synthesize it automatically? Given the space of possible rewrites explored by the synthesizer, we believe that it can currently produce at most \PercentPossibleToSynth{} of rules that exist in the current TRS. The obstacles to synthesizing all human-written rules include (i)~the inability to automatically verify some rules or preconditions (see Question 3 above); and (ii)~lack of support for some operators in our synthesizer.

We tested the synthesizer's ability to recreate the original ruleset in the following experiment. We instrumented the ruleset to associate expressions from compilations of Halide's correctness test suite with individual rules invoked when those expressions are rewritten. We gathered a set of rules for which we had at least three expressions that matched the rule, and filtered out those rules that are out of scope for the current synthesizer, because their right-hand sides contain operators we do not support. This gave us a set of \NumRulesInCorrectnessExperiment{} rules. For each of these rules, we disabled the rule in the TRS, then used its matching expressions as input to the synthesizer. The synthesizer was able to find rules in 186 cases, or about \PercentRulesResynthesized{} of the rules. Of the other 135 cases, in 43 of them other rules in the existing TRS happened to combine to rewrite the specific input expression even without the target rule; for example, this often occurred when the matching expression contained combinations of constants that could be exploited by other rules. 10 of the 92 failure cases were due to timeouts in the synthesis process, while 15 specifically failed to synthesize a predicate. Given that it was difficult to target the desired rule precisely, we found this to be promising; efforts to synthesize a term rewriting system entirely from scratch are described in chapter~\ref{chapter:synthfromscratch}.

\subsection{Practical Uses of the Synthesizer and Verifier}

\subsubsection{What is the Best Way to Use Synthesis and Verification in Development?}
\label{sub:synthassistant}

% Is the expert equipped with the synthesizer better at developing rules than either the expert alone or the synthesizer alone? The synthesizer can accelerate rule development because it is correct by construction and also faster than a human expert. On average, the expert needed about 30 minutes to develop a rule, including a paper proof and the code review. Our synthesizer typically produces a batch of ten (verified) rules in about 5 minutes.

We have found that human experts can leverage the strengths of the synthesis tool by using it as an assistant: for example by synthesizing a rule and then generalizing or simplifying it by hand, or by writing a rule and asking the tool to synthesize a valid predicate. Most importantly, this avoids committing new bugs, but it also accelerates rule development. Halide developers report that adding new rules by hand takes about 30 minutes per rule starting from sample input expressions through final review. Starting from the same input expressions, the synthesis tool can produce a batch of 10 verified rules in about 5 minutes.

Here we survey some cases from recent Halide development where the synthesis machinery was used in this way, labeled here as $\mathbb{F}$ through $\mathbb{I}$. The diffs are available as  on the Halide project website\footnote{
$\mathbb{F}$: \url{https://github.com/halide/Halide/pull/4721} \\
$\mathbb{G}$: \url{https://github.com/halide/Halide/pull/4772} \\
$\mathbb{H}$: \url{https://github.com/halide/Halide/pull/4439} \\% these are the div by 0 semantics change fixes
$\mathbb{I}$: \url{https://github.com/halide/Halide/pull/4850}
}.

In case $\mathbb{F}$ a Halide developer encountered expressions that seemed like they could be simpler while working on real code, and rather than inventing a rule from scratch searched the logs of the synthesizer project for a known-correct synthesized rule that handled the case in question. This added four new rules that are variants of:
\[
\hmax(y, z) < \hmin(x, y) \rewrites \mathit{false}
\]
In case $\mathbb{G}$ a developer wrote 24 new rules, proving them on paper, and then checked their work by resynthesizing the predicates using the synthesizer, ensuring that the synthesized predicates agreed with the human’s and that those predicates were as broad as possible. Here the synthesis machinery served as a reviewer of rules rather than an author. Eight of these rules were in fact manual rederivations of the synthesizer’s output on case $\mathbb{D}$ above. The remaining 16 are generalizations that add constant terms. One example:
\[
\hmin(y + c_0, z) < \hmin(y, x) \rewrites \hmin(z, y + c_0) < x \pred c_0 < 0
\]

Halide endeavors to be a safe language, meaning that certain things are checked at compile time or runtime rather than being undefined behavior. In case $\mathbb{I}$, Halide was changed such that instead of asserting that no output value has a dependency on any out-of-bounds input values, it now asserts the stricter condition that no out-of-bounds loads occur on the input, even if those loaded values cannot possibly affect an output.

This is a harder thing for the compiler to check, and analysis often conservatively found that it was possible for code to read out of bounds, when in fact it would not. The Halide developers ameliorate this in part by minimizing the number of non-monotonic expressions using aggressive simplification. In total 59 new rewrite rules were added as part of this change. Eight of these were synthesized automatically by copy-pasting a non-monotonic expression from a bug report into the synthesis machinery. Another 28 came from generalizing those rules by hand and then verifying the result. Twenty more were written by hand and then verified. Finally, there were three rules that could not be verified, because they involve the interaction of division and modulus. During this process a large number of bugs were found in human-written early versions of these rules. We found that with the verifier and synthesizer in hand, humans work quickly and rely on the machinery to catch their mistakes.

Generalizing from these four cases, we have found that having the verifier and synthesizer available as tools reduces the number of bugs committed, uncovers and fixes old bugs, and helps developers work more quickly by not only mechanizing correctness checking but also by synthesizing correct code. We also found that the guarantees these tools provide mean that the developers can make large changes to the compiler with confidence. Anecdotally, developers also report that eliminating these classes of bug makes triaging new issues simpler, because they could now not possibly be due to an incorrect rule or an infinite loop in the term rewriting system.

\subsection{Using the Synthesizer to Prevent Future Issues}
\label{ssec:compilationspeed}

\subsubsection{Can Synthesis be Used for Large-scale Improvements of the TRS?\nopunct}
\label{sub:endtoendexperiment}
%What improvements are possible when we allow the synthesizer to learn rules from a large body of input, without human supervision? In this experiment, rather than synthesizing a repair to just one incorrect rule, we attempted to synthesize rules for over 100,000 expressions that failed to simplify over thousands of instrumented compilations. We synthesized 4127 rules and added them to the TRS. In evaluating the effects of these improvements, we found 197 benchmarks that were over-allocating memory, sometimes dramatically, due to imprecise bounds reasoning caused by missing rules. Those benchmarks were fixed by the improved TRS. Synthesis allowed us to make this dramatic change to the ruleset without fear of introducing non-terminating behavior, since synthesized rules must satisfy the reduction order (see Section~\ref{sub:termination}). Satisfying this additional restriction would further complicate manual rule development.

%% AA: I found the above paragraph redundant with the summary at the start of the section and the more detail version below. If we want an intro para here I think it should be shorter.

Although we now have a guarantee of soundness, we have no such guarantee of completeness. There are almost certainly Halide compilations for which the addition of some desirable rule would strengthen the TRS enough to unlock some optimization or achieve a tighter bound on some region. However, we don’t know what they are because no human has encountered them yet (or more likely, no human has been sufficiently motivated to submit a bug report for them yet).

We attempted to probe for such opportunities for improvement using fuzzing. We selected the 12 most complex example applications in the open source repository, and generated 64 random schedules for each using the autoscheduler~\citep{Adams2019}, which can be configured to generate random likely-good schedules. This produced 768 separate compilations. We also instrumented most of the Halide code at Google for an additional 5032 compilations, this time using the original human-written schedules. Note that this is qualitatively different to randomly-generated schedules: we do not expect Halide users at Google would check in code that behaves poorly due to an issue with the compiler.

We instrumented these compilations to log expressions that might represent a TRS failure of some kind. From each compilation we log all integer expressions found that are non-monotonic with respect to a containing loop, and all failed proof attempts made during compilation. That is, we log all boolean expressions passed to the TRS in the hope that they will reduce to the constant true so that some optimization can correctly be performed. This resulted in a corpus of roughly one hundred thousand unique expressions.

Using this corpus as input, we synthesize new rewrite rules, add all rules found back to the ruleset, and rerun all compilations to gather new expressions, repeating this process until convergence. In total we created 4127 new rewrite rules in this way, more than quadrupling the number of rules in the TRS. For some examples, refer to Table \ref{tab:samplerules}.

We then generate a fresh set of 256 random schedules per application (to avoid testing on our training set), and compile and run all the generated code, looking for any compilations which behave significantly differently between the baseline condition (compiled using unmodified Halide) and the test condition (compiled with the 4127 additional rewrite rules). The interesting findings are summarized below.

\paragraph{Adding new rules lowers peak memory usage by up to 50\%}
Halide sizes internal allocations using symbolic interval arithmetic,
which (as described in Section~\ref{sec:synthesizing-candidate-rules})
is prone to overestimating bounds when
expressions do not either monotonically increase or decrease with
respect to some containing loop. By extending the TRS, we
automatically fix 197 cases where this kind of error increases the
peak memory usage of an application at runtime by more than 10\%, including one
case where the increase was more than a gigabyte. This represents
nearly 6\% of all compilations tested. We believe this captures a
widespread problem, as instances of overallocation are a common source
of complaint from users. See Figure~\ref{fig:peakmemoryhistogram} for
the full distribution.

\begin{figure*}
\centering
  \includegraphics[width=4in]{figures/memoryhistogram.pdf}
\caption{Reduction in runtime peak memory usage of 3072 pieces of compiled
  code when 4127 synthesized rules are added to the TRS. The x-axis
  shows $\frac{after}{before}$, so below 1.0 means the synthesized rules
  reduced memory consumption.  In 197 cases,
  peak memory usage drops by more than 10\%.}
\label{fig:peakmemoryhistogram}
\end{figure*}

\paragraph{Term rewriting systems written without verification have bugs}
On our initial run of this experiment, 55 compilations (1.6\%) crashed
at runtime with memory corruption errors in the baseline condition (no
new rules added). We traced this to an incorrect transformation in the variable solver, which had never been verified (and was not yet implemented as a formal TRS). This
bug had existed for four years, but had only recently become an
important code path due to change $\mathbb{I}$ mentioned above. The
incorrect transformation was $\hmin(x - y, x - z) \rewrites x - \hmin(y, z)$,
which should be $\hmin(x - y, x - z) \rewrites x - \hmax(y, z)$. If this
secondary TRS had been written using verification, this bug would
never have been introduced. We discuss efforts to replace the current implementation of the variable solver with a correct-by-construction TRS in chapter~\ref{chapter:synthfromscratch}.

\paragraph{The TRS scales well with the number of rules}
Remarkably, more than quadrupling the size of the TRS increased total compile
times by only 0.3\%. On further examination we found that the
additional rules increased the amount of time spent inside the TRS by
30\%, and that only 1\% of the the total compile time of the average
Halide program is spent inside the TRS.

We did not find significant effects on runtime of the generated code or code size. We also found no significant differences on any metrics within the Google corpus. This may be because the random schedules we generate are especially complex compared to human-written ones, or simply because humans don't commit code that causes the compiler to misbehave.

While adding the synthesized rules does not come at any significant cost we could measure to users of Halide, Halide developers were reluctant to add the full 4,000 rule set for two reasons. One is that adding 4,000 lines of code to the simplifier caused a significant slowdown in the compilation time of the Halide compiler itself, which was burdensome for compiler developers. The other was that while the thousand handwritten rules were difficult for programmers to reason about and maintain, adding 4,000 more rules made it almost completely unreadable. In the summer of 2021, Evan Lee of the University of Waterloo undertook a Google Summer of Code project to analyze which rules were crucial to the performance gains observed above. He found that the AC variants of 11 rules, or 31 rules overall, were sufficient to realize the performance gains on the standard application suite benchmarks. Those rules were merged into the Halide codebase in August 2021\footnote{\url{https://github.com/halide/Halide/pull/6174}}.

These results show that having verification and synthesis available as a tool for compiler authors fixes existing bugs, prevents entire classes of new bugs, and even helps compiler writers change the semantics of their language with confidence. Halide developers plan to continue to use verification and synthesis to maintain the TRS, and based on this experience plan to expand its use elsewhere in the compiler.

\section{Limitations \& Future Work}
\label{sec:limitations}

For this work, we considered only the subset of the term rewriting system that
is used to prove properties over infinite integers; the full TRS includes rules
for simplifying expressions with floating point values as well as rules for
fixed-bitwidth integers.  As a result, we do not consider cases where the TRS
must also reason about whether overflow can occur.  Extending our improvements
and automation to such rules could be done in future work.

One major limitation of the synthesis process we use is that our solver,
Z3, often cannot reason about expressions with divisions or modulo
where the right operand is a variable.  Though we work around this to
synthesize rules with generalized predicates on right hand side constants,
the overall synthesis machinery cannot generalize these to non-constants.
Extending the synthesizer may be more tractable for rules that operate
on integers with finite bitwidths.


\documentclass[12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{float}
\usepackage{amsmath}

\usepackage[hmargin=3cm,vmargin=6.0cm]{geometry}
%\topmargin=0cm
\topmargin=-2cm
\addtolength{\textheight}{6.5cm}
\addtolength{\textwidth}{2.0cm}
%\setlength{\leftmargin}{-5cm}
\setlength{\oddsidemargin}{0.0cm}
\setlength{\evensidemargin}{0.0cm}

\newcommand{\HRule}{\rule{\linewidth}{1mm}}

%misc libraries goes here
\usepackage{tikz}
\usetikzlibrary{automata,positioning}

\begin{document}

\noindent
\HRule \\[3mm]
\begin{flushright}

                                         \LARGE \textbf{CENG 222}  \\[4mm]
                                         \Large Statistical Methods for Computer Engineering \\[4mm]
                                        \normalsize      Spring '2018-2019 \\
                                           \Large   Homework 4 \\
\end{flushright}
\HRule

\section*{Student Information }
%Write your full name and id number between the colon and newline
%Put one empty space character after colon and before newline
Full Name : Yavuz Selim Yesilyurt \\
Id Number : 2259166

% Write your answers below the section tags
\section*{Answer 9.10}
The given information describes that the from a sample of 200 items 24 defective items were found. We can calculate the sample proportion of defective items as follows:
\begin{align*}
\hat{p} &= \frac{x}{n} \\
		&= \frac{24}{200} \\
		&= 0.12
\end{align*}
Also, for the 96\% confidence interval we will have a significance level of $\alpha = 0.04$ and from standard normal table we can check its value which is 2.054. \\

\subsection*{a)}
With the information we obtained above, let us construct a 96\% confidence interval for the proportion of defective items as follows:
\begin{align*}
\text{96\% Confidence Interval} &= \hat{p} +_- Z_{critical}\sqrt{\frac{\hat{p}(1-\hat{p})}{n}} \\
&= 0.12 +_- 2.054\sqrt{\frac{0.12(1-0.12)}{200}} \\
&= 0.12 +_- 0.047 \\
&= (0.073, 0.167)
\end{align*}

\subsection*{b)}
First let us state our hypotheses: \\
\begin{center}
$H_0:p\leq 0.1$ and $H_A:p > 0.1$ \\
\end{center}
And as level of significance we have $\alpha = 0.04$ and $\alpha = 0.15$ values. Let us calculate the test statistic and then find the $p$ value to determine whether to accept or reject the Null hypothesis ($H_0$):
\begin{align*}
Z &= \frac{\hat{p}-p}{\sqrt{\frac{p(1-p)}{n}}} \\
  &= \frac{0.12-0.1}{\sqrt{\frac{0.1(1-0.1)}{200}}} \\
  &= \frac{0.02}{0.0212} \\
  &= 0.943
\end{align*}
Find the $p$ value:
\begin{align*}
p &= P(Z > Z_0) \\
  &= 1 - P(Z \leq 0.943) \\
  &= 1 - 0.82716 \ \ \text{(From Std Norm Table)} \\
  &= 0.17284
\end{align*}
In Conclusion, we see that the $p$ value (0.17284) is greater than the given significance levels (0.04 and 0.15), so we fail to reject the null hypothesis and conclude that there would be sufficient evidence to say that the claim is incorrect.

\newpage
\section*{Answer 9.12}
We are given: \\
\begin{center}
$\bar{x} = 0.62$, $\sigma = 0.2$ and $n = 52$.
\end{center}

\subsection*{a)}
To construct a 95\% confidence interval for the population mean resistance first let us find our level of significance at 95\% which is $\alpha = 0.05$ and from Standard Normal table it has value of 1.96.
So:
\begin{align*}
\text{95\% Confidence Interval} &= \bar{x} +_- Z_{critical}(\frac{\sigma}{\sqrt{n}}) \\
&= 0.62 +_- 1.96(\frac{0.2}{\sqrt{52}})\\
&= 0.62 +_- 0.05436 \\
&= (0.56564 < \mu < 0.67436)
\end{align*}

\subsection*{b)}
The probability that resistance is 0.62 ohms or higher can be found as follows:
\begin{align*}
P(X > 0.62) &= 1-P(Z \leq 0.62) \\
			&= 1-P(Z \leq \frac{0.62-0.6}{0.2 / \sqrt{52}}) \\
			&= 1-P(Z \leq 0.721) \\
			&= 1-0.764545 \ \ \text{(From Std Norm Table)} \\
			&= 0.235455
\end{align*}

\newpage
\section*{Answer 10.3}
From the given random number generator data with $N=100$, after arranging data into increasing order, let us form a continuous type frequency table of the data which is given below:

\begin{table}[h]
\begin{tabular}{|l|l|}
\hline
Class interval & Frequency \\ \hline
below -2.0     & 4         \\ \hline
-2.0 to -1.5   & 4         \\ \hline
-1.5 to -1.0   & 15        \\ \hline
-1.0 to -0.5   & 9         \\ \hline
-0.5 to 0      & 22        \\ \hline
0 to 0.5       & 15        \\ \hline
0.5 to 1.0     & 12        \\ \hline
1.0 to 1.5     & 11        \\ \hline
1.5 to 2.0     & 7         \\ \hline
2.0 and above  & 1         \\ \hline
Total          & 100       \\ \hline
\end{tabular}
\end{table}
\subsection*{a)}
Using the table of normal distribution; the table of expected, observed frequencies and other required columns comes out to be:

\begin{table}[h]
\begin{tabular}{|l|l|l|l|}
\hline
Class interval & $obs_i$ & $exp_i$ & $\chi^2$ \\ \hline
below -2.0     & 4      & 3.32   & 0.14                                   \\ \hline
-2.0 to -1.5   & 4      & 5.32   & 0.33                                   \\ \hline
-1.5 to -1.0   & 15     & 10.02  & 2.48                                   \\ \hline
-1.0 to -0.5   & 9      & 15.14  & 2.49                                   \\ \hline
-0.5 to 0      & 22     & 18.38  & 0.71                                   \\ \hline
0 to 0.5       & 15     & 17.92  & 0.48                                   \\ \hline
0.5 to 1.0     & 12     & 14.03  & 0.29                                   \\ \hline
1.0 to 1.5     & 11     & 8.82   & 0.54                                   \\ \hline
1.5 to 2.0     & 7      & 4.46   & 1.45                                   \\ \hline
2.0 and above  & 1      & 2.59   & 0.97                                   \\ \hline
Total          & 100    & 100    & 9.88332                                \\ \hline
\end{tabular}
\end{table}
Now to test the hypothesis at 5\% significance level whether the given data follows a normal distribution, we need to calculate the test statistic, which can be calculated as follows:
\begin{align*}
\chi^2 &= \Sigma\frac{(obs_i - exp_i)^2}{exp_i} \\
	   &= 9.88
\end{align*}
And degrees of freedom in this case is:
\begin{align*}
v &= n-1 \\
  &= 10-1 \\
  &= 9
\end{align*}
The $p$ value for the above value of test statistic at 9 degrees of freedom can be found from table A6 and founded to be between 0.2 and 0.8, which is more than the significance level 0.05. We conclude that there is no evidence against the data follows a normal distribution.

\subsection*{b)}
The pdf of Uniform distribution is given by:
\begin{center}
$f(x) = \frac{1}{b-a} \ \ a \leq x \leq b$ \\
\end{center}

In this problem we have our $a=-3$, $b=3$. We need to calculate the table of expected, observed frequencies and other required columns again for Uniform distribution, which comes out to be:

\begin{table}[h]
\begin{tabular}{|l|l|l|l|}
\hline
Class interval & $obs_i$ & $exp_i$ & $\chi^2$ \\ \hline
below -2.0     & 4      & 16.67  & 9.63                                   \\ \hline
-2.0 to -1.5   & 4      & 8.33   & 2.25                                   \\ \hline
-1.5 to -1.0   & 15     & 8.33   & 5.33                                   \\ \hline
-1.0 to -0.5   & 9      & 8.33   & 0.05                                   \\ \hline
-0.5 to 0      & 22     & 8.33   & 22.41                                  \\ \hline
0 to 0.5       & 15     & 8.33   & 5.33                                   \\ \hline
0.5 to 1.0     & 12     & 8.33   & 1.61                                   \\ \hline
1.0 to 1.5     & 11     & 8.33   & 0.85                                   \\ \hline
1.5 to 2.0     & 7      & 8.33   & 0.21                                   \\ \hline
2.0 and above  & 1      & 16.67  & 14.73                                  \\ \hline
Total          & 100    & 100    & 62.42                                  \\ \hline
\end{tabular}
\end{table}

Now to test the hypothesis at 5\% significance level whether the given data follows a Uniform distribution, we need to calculate the test statistic, which can be calculated as follows:
\begin{align*}
\chi^2 &= \Sigma\frac{(obs_i - exp_i)^2}{exp_i} \\
	   &= 62.42
\end{align*}
And degrees of freedom in this case is:
\begin{align*}
v &= n-1 \\
  &= 10-1 \\
  &= 9
\end{align*}
The $p$ value for the above value of test statistic at 9 degrees of freedom can be found from table A6 and founded to be $<0.001$, which is much lower than the significance level 0.05. We conclude that there is strong evidence against the data follows a Uniform distribution.

\subsection*{c)}
According to the central limit theorem, theoretically it is possible that a data follows Normal and Uniform distributions simultaneously for a large sample.

\section*{Answer 10.9}
Let us first state our Null and Alternative hypotheses:

\begin{center}
$H_0:$ all three section's performance is equal \\
$H_A:$ all three section's performance is not equal \\
\end{center}
We have our level of significance as $\alpha = 0.05$. Now let us again create a table of expected, observed frequencies and other required columns and perform a Chi-Square test. Note that this time we have 3 samples and we will draw the table in a slightly different fashion. Each column shows a section and each row shows a grade. There are three numbers in each entry which corresponds to:
\begin{center}
Observed \\
Observed - Expected \\
$\chi^2$
\end{center}

\begin{table}[h]
\begin{tabular}{|c|c|c|c|c|}
\hline
Grade & S01                                                        & S02                                                        & S03                                                        & Total                                                      \\ \hline
A     & \begin{tabular}[c]{@{}c@{}}40\\ 5.71\\ 0.95\end{tabular}  & \begin{tabular}[c]{@{}c@{}}20\\ -8.57\\ 2.57\end{tabular} & \begin{tabular}[c]{@{}c@{}}20\\ 2.86\\ 0.48\end{tabular}  & \begin{tabular}[c]{@{}c@{}}80\\ 0\\ 4\end{tabular}      \\ \hline
B     & \begin{tabular}[c]{@{}c@{}}50\\ 2.86\\ 0.17\end{tabular}  & \begin{tabular}[c]{@{}c@{}}40\\ 0.71\\ 0.01\end{tabular}  & \begin{tabular}[c]{@{}c@{}}20\\ -3.57\\ 0.54\end{tabular} & \begin{tabular}[c]{@{}c@{}}110\\ 0\\ 0.73\end{tabular}  \\ \hline
C     & \begin{tabular}[c]{@{}c@{}}20\\ -5.71\\ 1.27\end{tabular} & \begin{tabular}[c]{@{}c@{}}25\\ 3.57\\ 0.6\end{tabular}   & \begin{tabular}[c]{@{}c@{}}15\\ 2.14\\ 0.36\end{tabular}  & \begin{tabular}[c]{@{}c@{}}60\\ 0\\ 2.22\end{tabular}   \\ \hline
D     & \begin{tabular}[c]{@{}c@{}}2\\ -1.86\\ 0.89\end{tabular}  & \begin{tabular}[c]{@{}c@{}}5\\ 1.79\\ 0.99\end{tabular}   & \begin{tabular}[c]{@{}c@{}}2\\ 0.07\\ 0\end{tabular}      & \begin{tabular}[c]{@{}c@{}}9\\ 0\\ 1.89\end{tabular}    \\ \hline
F     & \begin{tabular}[c]{@{}c@{}}8\\ -1\\ 0.11\end{tabular}     & \begin{tabular}[c]{@{}c@{}}10\\ 2.5\\ 0.83\end{tabular}   & \begin{tabular}[c]{@{}c@{}}3\\ -1.5\\ 0.5\end{tabular}    & \begin{tabular}[c]{@{}c@{}}21\\ 0\\ 1.44\end{tabular}   \\ \hline
Total & \begin{tabular}[c]{@{}c@{}}120\\ 0\\ 3.4\end{tabular}     & \begin{tabular}[c]{@{}c@{}}100\\ 0\\ 5.01\end{tabular}    & \begin{tabular}[c]{@{}c@{}}60\\ 0\\ 1.88\end{tabular}     & \begin{tabular}[c]{@{}c@{}}280\\ 0\\ 10.28\end{tabular} \\ \hline
\end{tabular}
\end{table}
As can be seen from the last row, last column of our table, $\chi^2$ of the total is equal to 10.28 and we have a $v = 8$ degrees of freedom. \\

The $p$ value for the above value of test statistic at 8 degrees of freedom can be found from table A6 and founded to be between 0.8 and 0.2, which is greater than the significance level 0.05. \\

So in conclusion, Since, the $p$ value greater than the given significance level 0.05, so we fail to reject the null hypothesis and conclude that the three sections performance is equal.

\end{document}


\section{Built-in Module \sectcode{rotor}}
\bimodindex{rotor}

This module implements a rotor-based encryption algorithm, contributed by
Lance Ellinghouse.  The design is derived from the Enigma device, a machine
used during World War II to encipher messages.  A rotor is simply a
permutation.  For example, if the character `A' is the origin of the rotor,
then a given rotor might map `A' to `L', `B' to `Z', `C' to `G', and so on.
To encrypt, we choose several different rotors, and set the origins of the
rotors to known positions; their initial position is the ciphering key.  To
encipher a character, we permute the original character by the first rotor,
and then apply the second rotor's permutation to the result. We continue
until we've applied all the rotors; the resulting character is our
ciphertext.  We then change the origin of the final rotor by one position,
from `A' to `B'; if the final rotor has made a complete revolution, then we
rotate the next-to-last rotor by one position, and apply the same procedure
recursively.  In other words, after enciphering one character, we advance
the rotors in the same fashion as a car's odometer. Decoding works in the
same way, except we reverse the permutations and apply them in the opposite
order.
\index{Ellinghouse, Lance}
\indexii{Enigma}{cipher}

The available functions in this module are:

\renewcommand{\indexsubitem}{(in module rotor)}
\begin{funcdesc}{newrotor}{key\optional{\, numrotors}}
Return a rotor object. \var{key} is a string containing the encryption key
for the object; it can contain arbitrary binary data. The key will be used
to randomly generate the rotor permutations and their initial positions.
\var{numrotors} is the number of rotor permutations in the returned object;
if it is omitted, a default value of 6 will be used.
\end{funcdesc}

Rotor objects have the following methods:

\renewcommand{\indexsubitem}{(rotor method)}
\begin{funcdesc}{setkey}{}
Reset the rotor to its initial state.
\end{funcdesc}

\begin{funcdesc}{encrypt}{plaintext}
Reset the rotor object to its initial state and encrypt \var{plaintext},
returning a string containing the ciphertext.  The ciphertext is always the
same length as the original plaintext.
\end{funcdesc}

\begin{funcdesc}{encryptmore}{plaintext}
Encrypt \var{plaintext} without resetting the rotor object, and return a
string containing the ciphertext.
\end{funcdesc}

\begin{funcdesc}{decrypt}{ciphertext}
Reset the rotor object to its initial state and decrypt \var{ciphertext},
returning a string containing the ciphertext.  The plaintext string will
always be the same length as the ciphertext.
\end{funcdesc}

\begin{funcdesc}{decryptmore}{ciphertext}
Decrypt \var{ciphertext} without resetting the rotor object, and return a
string containing the ciphertext.
\end{funcdesc}

An example usage:
\bcode\begin{verbatim}
>>> import rotor
>>> rt = rotor.newrotor('key', 12)
>>> rt.encrypt('bar')
'\2534\363'
>>> rt.encryptmore('bar')
'\357\375$'
>>> rt.encrypt('bar')
'\2534\363'
>>> rt.decrypt('\2534\363')
'bar'
>>> rt.decryptmore('\357\375$')
'bar'
>>> rt.decrypt('\357\375$')
'l(\315'
>>> del rt
\end{verbatim}\ecode

The module's code is not an exact simulation of the original Enigma device;
it implements the rotor encryption scheme differently from the original. The
most important difference is that in the original Enigma, there were only 5
or 6 different rotors in existence, and they were applied twice to each
character; the cipher key was the order in which they were placed in the
machine.  The Python rotor module uses the supplied key to initialize a
random number generator; the rotor permutations and their initial positions
are then randomly generated.  The original device only enciphered the
letters of the alphabet, while this module can handle any 8-bit binary data;
it also produces binary output.  This module can also operate with an
arbitrary number of rotors.

The original Enigma cipher was broken in 1944. % XXX: Is this right?
The version implemented here is probably a good deal more difficult to crack
(especially if you use many rotors), but it won't be impossible for
a truly skilful and determined attacker to break the cipher.  So if you want
to keep the NSA out of your files, this rotor cipher may well be unsafe, but
for discouraging casual snooping through your files, it will probably be
just fine, and may be somewhat safer than using the Unix \file{crypt}
command.
\index{National Security Agency}\index{crypt(1)}
% XXX How were Unix commands represented in the docs?


\documentclass{beamer}

\usepackage{xcolor}
\usepackage{amsmath,amssymb}
\usepackage{tikz}
\usepackage{tikz-cd}
\usepackage{graphicx}

\usetikzlibrary{shapes.geometric}

\tikzset{pics/.cd,
opencube/.style args={#1/#2/#3}{code={
\coordinate (O) at (0,0,0);
\coordinate (A) at (0,#2,0);
\coordinate (B) at (0,#2,#3);
\coordinate (C) at (0,0,#3);
\coordinate (D) at (#1,0,0);
\coordinate (E) at (#1,#2,0);
\coordinate (F) at (#1,#2,#3);
\coordinate (G) at (#1,0,#3);
%% Background
\draw[black,dotted] (O) -- (A);
\draw[black,dotted] (O) -- (C);
\draw[black,dotted] (O) -- (D);
% Forground
\draw[black,dashed] (A) -- (E) -- (F) -- (B) -- cycle;
\draw[black,dashed] (E) -- (D) -- (G) -- (C) -- (B);
\draw[black,dashed] (F) -- (G);

%\draw[black,dashed, blue] (O) -- (A) -- (E) -- (D) -- cycle;
%\draw[black,dashed] (O) -- (A) -- (B) -- (C) -- cycle;
%\draw[black,dashed] (D) -- (E) -- (F) -- (G) -- cycle;
%\draw[black,dashed] (C) -- (B) -- (F) -- (G) -- cycle;
%\draw[black,dashed] (A) -- (B) -- (F) -- (E) -- cycle;

}}}

\tikzset{pics/.cd,
linecube/.style args={#1/#2/#3/#4}{code={
\coordinate (OO) at (0,0,0);
\coordinate (AA) at (0,#2,0);
\coordinate (BB) at (0,#2,#3);
\coordinate (CC) at (0,0,#3);
\coordinate (DD) at (#1,0,0);
\coordinate (EE) at (#1,#2,0);
\coordinate (FF) at (#1,#2,#3);

\coordinate (GG) at (#1,0,#3);
%% Background
\draw[black,dashed] (OO) -- (AA);
\draw[black,dashed] (OO) -- (CC);
\draw[black,dashed] (OO) -- (DD);

\node at (0.5*#1,0.5*#2,0.5*#3) {#4};

% Foreground
\draw[black] (AA) -- (EE) -- (FF) -- (BB) -- cycle;
\draw[black] (EE) -- (DD) -- (GG) -- (CC) -- (BB);
\draw[black] (FF) -- (GG);

%\draw[black,dashed, blue] (O) -- (A) -- (E) -- (D) -- cycle;
%\draw[black,dashed] (O) -- (A) -- (B) -- (C) -- cycle;
%\draw[black,dashed] (D) -- (E) -- (F) -- (G) -- cycle;
%\draw[black,dashed] (C) -- (B) -- (F) -- (G) -- cycle;
%\draw[black,dashed] (A) -- (B) -- (F) -- (E) -- cycle;

}}}

\tikzset{pics/.cd,
shadedcube/.style args={#1/#2/#3/#4/#5}{code={
\coordinate (O) at (0,0,0);
\coordinate (A) at (0,#2,0);
\coordinate (B) at (0,#2,#3);
\coordinate (C) at (0,0,#3);
\coordinate (D) at (#1,0,0);
\coordinate (E) at (#1,#2,0);
\coordinate (F) at (#1,#2,#3);
\coordinate (G) at (#1,0,#3);
\draw[black,fill=#4!80] (O) -- (C) -- (G) -- (D) -- cycle;
\draw[black,fill=#4!30] (O) -- (A) -- (E) -- (D) -- cycle;
\draw[black,fill=#4!10] (O) -- (A) -- (B) -- (C) -- cycle;
\draw[black,fill=#4!20,opacity=0.8] (D) -- (E) -- (F) -- (G) -- cycle;
\draw[black,fill=#4!20,opacity=0.6] (C) -- (B) -- (F) -- (G) -- cycle;
\draw[black,fill=#4!20,opacity=0.8] (A) -- (B) -- (F) -- (E) -- cycle;
\node at (0.5*#1,0.5*#2,0.5*#3) {#5};
}}}
\tikzset{pics/.cd,
gridcube/.style args={#1/#2/#3/#4/#5/#6/#7}{code={
\coordinate (O) at (0,0,0);
\coordinate (A) at (0,#2,0);
\coordinate (B) at (0,#2,#3);
\coordinate (C) at (0,0,#3);
\coordinate (D) at (#1,0,0);
\coordinate (E) at (#1,#2,0);
\coordinate (F) at (#1,#2,#3);
\coordinate (G) at (#1,0,#3);

% Foreground
\draw[fill=#7!20] (A) -- (E) -- (F) -- (B) -- cycle;
\draw[fill=#7!40] (E) -- (F) -- (G) -- (D) -- cycle;
\draw[fill=#7!30] (B) -- (F) -- (G) -- (C) -- cycle;
%\draw[black] (E) -- (D) -- (G) -- (C) -- (B);
%\draw[black] (F) -- (G);

% lines
\foreach \ll in {1,...,#4} {
    \draw[black] (#1/#4*\ll,#2,0) -- (#1/#4*\ll,#2,#3) -- (#1/#4*\ll,0,#3);
}
\foreach \ll in {1,...,#5} {
    \draw[black] (0,#2/#5*\ll,#3) -- (#1, #2/#5*\ll,#3) -- (#1,#2/#5*\ll,0);
}
\foreach \ll in {1,...,#6} {
    \draw[black] (0,#2,#3/#6*\ll) -- (#1,#2,#3/#6*\ll) -- (#1,0,#3/#6*\ll);
}

}}}

%\pgfmathsetmacro{\xx}{0.5}

\mode<presentation>
% \setbeameroption{hide notes}
{
  %\usetheme{Madrid}
  \usetheme{metropolis}
% CSU COLORS
  \definecolor{csugreen}{HTML}{1C674F}
  \definecolor{csugold}{HTML}{B78E00}
    \definecolor{csured}{HTML}{E02F11}

  \definecolor{greenmain}{HTML}{00AF64}
  \definecolor{brick}{rgb}{.85,.1,.2}
  \colorlet{greenstruct}{greenmain!87.5!black}
  \usecolortheme[named=csugreen]{structure}
  % Change this in order to make the presentation look
  % different. Works just like a powerpoint template.
  % Have your RA mess around until it looks nice.
  \setbeamercovered{dynamic}

  \useinnertheme{rectangles}

 %Other colors.

%   \definecolor{bluemain}{HTML}{0B61A4}
%   \definecolor{orangemain}{HTML}{AA6600}
%   \definecolor{redmain}{HTML}{E02F11}
%   \definecolor{redlight}{HTML}{FF9B73}
%   \definecolor{orangelight}{HTML}{FFC373}
%   \definecolor{cmugray}{RGB}{104,104,104}
%   \definecolor{cmulightgray}{RGB}{238,238,238}
%   \setbeamercolor{block body}{bg=cmulightgray}
%   \setbeamercolor{talktitle}{bg=csugreen,fg=white}
%   \setbeamercolor{block title alerted}{bg=csugold}
%   \setbeamercolor{block body alerted}{bg=orangelight}

}
\renewcommand{\footnoterule}{}
\renewcommand{\hat}[1]{\widehat{#1}}
\newcommand{\sourcenum}[3]{$^{\textcolor{bluemain} #1}$\let\thefootnote\relax
  \footnotetext{\begin{flush#2}\textcolor{bluemain}
      {\tiny $^{#1}$ #3}\end{flush#2}}}
\newcommand{\source}[2]{\let\thefootnote\relax\footnotetext{\begin{flush#1}
      \textcolor{bluemain}{\tiny Source: #2}\end{flush#1}}}

\DeclareMathOperator{\Span}{Span}
\DeclareMathOperator{\Pres}{Pres}
\DeclareMathOperator{\End}{End}
\newcommand{\bmto}{\rightarrowtail}

\usepackage{wasysym}
\newcommand{\den}[1]{\Leftcircle\hspace*{-1mm}#1\hspace*{-1mm} \Rightcircle}

\begin{document}

\title{Reliable Tensor Clusters}
\author{CC-BY 2021 James B. Wilson\\ Colorado State University}
%\date{\today}

\maketitle

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Applications}

\subsection{Data science}
\begin{frame}
    \begin{block}{Data}
        Results of measurement \& computation, e.g.\\[5pt]
        \centering
        \emph{Mercury is 2.5cm high in tube}.
    \end{block}

    \begin{block}{Information}
        data used to make a decision, e.g.\\[5pt]
        \centering
        \emph{Thermometer reads $38^{\circ}$F; I'll wear a coat.}
    \end{block}

    \begin{block}{The Data Problem}
        Turn data into information.
    \end{block}

\end{frame}

\begin{frame}
    \frametitle{Nutrition Matrix}
    Nutrients$\times$Produce data collected and used on diet problems.
    \bigskip

    \begin{tabular}{c|cccccc|}
             & Apple & Beef & Egg & Filbert & $\cdots$ & Strawberry \\
    \hline
    Carbs    & 13.8  & 1    & 2    & 4.8    & $\cdots$  & 7.7 \\
    Protein  & 0.3   & 20.7 & 17.1 & 3.9    &  & 0.7 \\
    Fat      & 0.2   & 7.4  & 14.4 & 1.3    &  & 0.3 \\
    $\vdots $ & $\vdots$ & & & & &\\
    \hline
    \end{tabular}

    \bigskip
    Substitute other examples\\
     minerals$\times$ mines, pollutants$\times$water-source,
    keywords$\times$authors
\end{frame}

\begin{frame}[fragile]
    \frametitle{Nutrition Tensor}
    Reality is more complex...
    \begin{center}
        Nutrients $\times$ Produce $\times$ Farms $\times$ Water Source $\times$ Fertilizer
    \end{center}
    \centering
    \pgfmathsetmacro{\xx}{0.5}
    \begin{tikzpicture}[scale=1.5]
        \pic at (1.25,1.25,0) {
            linecube={3.75/2.5/1.75/{
                \begin{tikzpicture}
                    \foreach \x/\xc in {1/blue,2/red,3/green} {
                        \pic at (1.25*\x,1.25*1,0.25) {gridcube={1/0.75/1/4/3/4/{\xc}}};
                    }
                    \foreach \x/\xc in {1/purple,2/brown,3/teal} {
                        \pic at (1.25*\x,1.25*2,0.25) {gridcube={1/0.75/1/4/3/4/{\xc}}};
                    }
                \end{tikzpicture}
            }}
        };
        \node[rotate=45] at (0.75,0.5,0) {Rain};
        \node[rotate=45] at (1.5,0.25,0) {Willamette};
        \node[rotate=45] at (2.5,0.25,0) {Deschutes};

        \node[rotate=-30] at (4.75,1,1) {{\small Crawford Farms}};
        \node[rotate=-30] at (4.75,0.9,0.5) {{\small Four Pines Ranch}};
        \node[rotate=-30] at (4.60,.9,0) {{\small Schlecter Farms}};
        \node[rotate=-30] at (4.75,0.8,-0.5) {{\small Thistledown Farms}};

        \node at (4,1.5,-1) {{\small Phosphate}};
        \node at (4,2,-1) {{\small Nitrogen}};

        \node (N) at (-1,2,-0.25) {{\small Nutrients}};
        \node (F) at (2,3,-0.75) {{\small Produce}};
        \draw[thick] (N) -- (1,1.25,0);
        \draw[thick] (N) -- (1,2.25,0);
        \draw[thick] (F) -- (1.5,2.5,-0.75);
        \draw[thick] (F) -- (2 ,2.5,-0.75);
        \draw[thick] (F) -- (2.5,2.5,-0.75);
    \end{tikzpicture}

\end{frame}

\begin{frame}

    \frametitle{First Approximation of Tensor}
        Fox coefficients $K$ and set $[n]=\{1,\ldots,n\}$.
\bigskip

        A \emph{hypermatrix} (some call it a ``tensor'') is a function
        $\Gamma:[d_1]\times \cdots\times [d_{\ell}]\to K$.

        \[K^{d_1\times\cdots\times d_{\ell}} = \{\Gamma:[d_1]\times \cdots\times [d_{\ell}]\to K\}.\]

    Technical matter: For general sets $X_1,\ldots, X_{\ell}$
    $\Gamma:X_1\times \cdots \times X_{\ell}\to K$ has \emph{finite support} (only finitely many nonzero values).

\end{frame}

\begin{frame}
    Data collection chooses bases for convenience/practicality/instrumentation/safety/laws/...
    \begin{itemize}
        \item Measure each fruit, farm, fertilizer  separately
        \item Choose nutrients a lab can measure (Carbs, Sugar, Vit. A, Vit. B...)
    \end{itemize}

    \bigskip
    \textbf{Data collection is basis dependent;\\
    Likely some qualities of nutrition are basis independent.}

    \begin{block}{The Tensor-Data Problem}
        Find basis invariant properties of tensor data.\\
        (This is now a math problem!)
    \end{block}

\end{frame}

\begin{frame}

    \frametitle{Second Approximation of Tensor}

    A function $\langle \Gamma |:K^{X_1}\times \cdots \times K^{X_{\ell}}\bmto K$ where
    \begin{align*}
        \langle \Gamma| u_1,\ldots, u_{\ell}\rangle
        & = \sum_{x_1\in X_1} \cdots \sum_{x_{\ell}\in X_{\ell}} \Gamma_{x_1\cdots x_{\ell}} u_{1x_1}\cdots u_{\ell x_{\ell}}.
    \end{align*}

    {\color{magenta} $\bmto$?}  Just reminds me to tell you this is same ``multi-linear''
    \begin{align*}
        & (\forall a) &
        \langle t|u_a+\lambda \tilde{u}_{a},u_{\bar{a}}\rangle
        & = \langle t|u_a,u_{\bar{a}}\rangle
        + \lambda \langle t|\tilde{u}_{a},u_{\bar{a}}\rangle
    \end{align*}

\end{frame}

\begin{frame}
    \frametitle{Example: Find change of basis matrices to get clusters}
    \pgfmathsetmacro{\xx}{0.5}
	\begin{tikzpicture}

		\node (T) at (-4,0,0) {\begin{tikzpicture}
			\pic at (0,0,0) {shadedcube={2*\xx/2*\xx/2*\xx/gray/}};
			%\draw [->] (0,0,0) -- (5,0,0)
			\node[rotate=90] at (2*\xx,0.5*\xx,-1*\xx) {{\small users}};
			\node[rotate=45] at (-0.7*\xx,2*\xx,0) {{\small time}};
			\node at (0.2*\xx,-1*\xx,0*\xx) {{\small words}};

			\draw (0*\xx,2*\xx,0*\xx) rectangle (2*\xx,3.3*\xx,0*\xx);
	%        \draw (0*\xx,2*\xx,0*\xx) rectangle (2*\xx,4*\xx,0*\xx);
			\draw (0*\xx,0*\xx,2*\xx) --++ (0*\xx,2*\xx,0*\xx)
			   --++ (0*\xx,0*\xx,2*\xx) --++ (0*\xx,-2*\xx,0*\xx) -- cycle;
			\draw (2*\xx,0*\xx,0*\xx) --++ (2*\xx,0*\xx,0*\xx)
			   --++ (0*\xx,0*\xx,2*\xx) --++ (-2*\xx,0*\xx,0*\xx) -- cycle;

			\node[rotate=45,xslant=0.5] at (0*\xx,1*\xx,3*\xx) {{\small X}};
			\node at (1*\xx,2.7*\xx,0) {{\small Y}};
			\node[xslant=0.5] at (3*\xx,0*\xx,1*\xx) {{\small Z}};

			\node at (5*\xx,1*\xx,0) {$\overset{?}{=}$};
			\node at (-5*\xx,1*\xx,0) {$(\exists X)(\exists Y)(\exists Z)$};
		\end{tikzpicture}};

		%% Weird bug, using label (A) arrows go wonky, using label (A0) all good.
		\node (A0) at (1,2,0) {\begin{tikzpicture}
			\pic at (\xx,-\xx,0) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (0,0,\xx) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (0,\xx,0) {opencube={2*\xx/-2*\xx/2*\xx}};
		\end{tikzpicture}};
		%% Weird bug, using label (A) arrows go wonky, using label (A0) all good.
		\node (A1) at (1,0,0) {\begin{tikzpicture}
			\pic at (\xx,-\xx,0) {shadedcube={\xx/\xx/2*\xx/gray/}};
			\pic at (0,0,0) {shadedcube={\xx/\xx/2*\xx/gray/}};
			\pic at (0,\xx,0) {opencube={2*\xx/-2*\xx/2*\xx}};
		\end{tikzpicture}};
		%% Weird bug, using label (A) arrows go wonky, using label (A0) all good.
		\node (A2) at (1,-2,0) {\begin{tikzpicture}
			\pic at (\xx,-\xx,0) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (0,-\xx,\xx) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (0,0,0) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (\xx,0,\xx) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (0,\xx,0) {opencube={2*\xx/-2*\xx/2*\xx}};
		\end{tikzpicture}};

	\end{tikzpicture}

    Then ask: \emph{What type?} \emph{Are they unique?} \emph{How to find them?}
\end{frame}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{The Tensor Product}

\begin{frame}
    \begin{block}{Main Idea}
        \centering
    Data table $\equiv$ Multiplication Table
    \end{block}
\bigskip

    So study multiplication tables.
\end{frame}

\begin{frame}
    For finite sets
    \begin{align*}
        \boxtimes & : R^m\times R^n \bmto R^{m\times n}
        &
        u\boxtimes v & = u v^{\dagger} = \begin{bmatrix} u_1 v_1 & \cdots & u_1 v_n \\ \vdots & & \vdots \\ u_m v_1 & \cdots & u_m v_n \end{bmatrix}.
    \end{align*}

    In general possibly infinite matrices, but finite support
    \begin{align*}
        \boxtimes & : R^X\times R^Y \bmto R^{X\times Y}
        &
        (u\boxtimes v)_{xy} & = u_x v_y.
    \end{align*}
\end{frame}

\begin{frame}
    \frametitle{The Tensor Product}

    A right $R$-modules has a presentation
    \[U_R=\Pres_R\langle X\mid S\rangle =R^X/\Span S\]

    A left $R$-module has a presentation
    \[{_R V}=\Pres_R\langle Y\mid T\rangle =R^Y/\Span T\]

    Their \textbf{Tensor Product} is
    \[ U\otimes_R V = R^{X\times Y}/(R^X\boxtimes T+S\boxtimes R^Y)\]
    along with the induced function
    \begin{align*}
    \otimes & :U\times V \bmto U\otimes_R V
    \\
    x\otimes y & = x\boxtimes y+(R^X\boxtimes T+S\boxtimes R^Y).
    \end{align*}
\end{frame}

\begin{frame}[fragile]
    $U_R=\Pres_R\langle X\mid S\rangle =R^X/\Span S$;
    ${_R V}=\Pres_R\langle Y\mid T\rangle =R^Y/\Span T$
    \bigskip

    \centering
    \begin{tikzpicture}
        \node at (0,0) {\begin{tikzcd}
            \Span S \arrow[d,phantom,"\times"]\arrow[r, hook]
                & R^X\arrow[d,phantom,"\times"] \arrow[r,two heads]
                    & U_R=\Span X\arrow[d,phantom,"\times"]  \\
            \Span T \arrow[r, hook]\arrow[d,"\boxtimes",tail]
                & R^Y\arrow[d,"\boxtimes",tail] \arrow[r,two heads]
                    & {_R V}=\Span Y\arrow[d,"\otimes",tail] \\
            R^X\boxtimes T+S\boxtimes R^Y \arrow[r, hook]
                 & R^{X\times Y} \arrow[r,two heads]
                     & U\otimes_R V   \\
        \end{tikzcd}};
    \end{tikzpicture}
\end{frame}

\begin{frame}{Example}
    \[(\mathbb{Z}/2\mathbb{Z}\oplus \mathbb{Z}/6\mathbb{Z}\oplus \mathbb{Z})\otimes (\mathbb{Z}/4\mathbb{Z}\oplus \mathbb{Z}/8\mathbb{Z})\]
    \textbf{Solution.}
    \begin{align*}
        \left.
            \begin{bmatrix}\mathbb{Z} & \mathbb{Z}\\ \mathbb{Z} & \mathbb{Z} \\ \mathbb{Z} & \mathbb{Z} \end{bmatrix}
            \middle/
        \left(
            \begin{bmatrix} \mathbb{Z} \\ \mathbb{Z}\\ \mathbb{Z}\end{bmatrix}
        \begin{bmatrix} 4\mathbb{Z} & 8\mathbb{Z}\end{bmatrix}
        +
        \begin{bmatrix} 2\mathbb{Z} \\ 6\mathbb{Z}\\ 0\mathbb{Z}\end{bmatrix}
        \begin{bmatrix} \mathbb{Z} & \mathbb{Z}\end{bmatrix}\right)
        \right.\\
        =
        \left.
            \begin{bmatrix}\mathbb{Z} & \mathbb{Z}\\ \mathbb{Z} & \mathbb{Z} \\ \mathbb{Z} & \mathbb{Z} \end{bmatrix}
            \middle/
            \begin{bmatrix}4\mathbb{Z}+2\mathbb{Z} & 8\mathbb{Z}+2\mathbb{Z}\\ 4\mathbb{Z}+6\mathbb{Z} & 8\mathbb{Z}+6\mathbb{Z} \\ 4\mathbb{Z}+0\mathbb{Z} & 8\mathbb{Z}+0\mathbb{Z} \end{bmatrix}
        \right.\\
        =
        \begin{bmatrix}\mathbb{Z}/2\mathbb{Z} & \mathbb{Z}/2\mathbb{Z}\\ \mathbb{Z}/2\mathbb{Z} & \mathbb{Z}/2\mathbb{Z} \\ \mathbb{Z}/4\mathbb{Z} & \mathbb{Z}/8\mathbb{Z} \end{bmatrix}
    \end{align*}
\end{frame}

\begin{frame}
    $\mathbb{Z}/2\mathbb{Z}\otimes \mathbb{Q}$

    \begin{block}{Solution}
    $\mathbb{Q}=\left\langle \frac{1}{1!},\frac{1}{2!},\frac{1}{3!},\ldots\right\rangle =\langle e_1,e_2,\ldots \mid e_n=(n+1)e_{n+1}\rangle$
    \begin{align*}
        \left.
        \mathbb{Z}^{[1]\times \mathbb{N}}
        \middle/
        \left(2\mathbb{Z}\boxtimes \mathbb{Z}^{\mathbb{N}}
        +\mathbb{Z}\boxtimes \begin{bmatrix} 1 & -2 & & \\  & 1 & -3 & \\  & & \ddots & \ddots \end{bmatrix}
        \right)
        \right.\\
        \only<6>{
            \left.
            \mathbb{Z}^{1\times \mathbb{N}}\middle/\mathbb{Z}\boxtimes \begin{bmatrix} 1 & -2 & & \\  & 1 & -3 & \\  & & \ddots & \ddots \end{bmatrix}
            \cong \mathbb{Q}
            \right.
        }
    \end{align*}
    \only<1-5>{
    \begin{align*}
        \begin{bmatrix} 1 & -2 & & \\  & 1 & -3 & \\  & & \ddots & \ddots \\ 2 & 0 \\ & 2 & 0 \\ & & \ddots & \ddots \end{bmatrix}
        \only<2>{\sim\begin{bmatrix} 1 & -2 & & \\  & 1 & -3 & \\  & & \ddots & \ddots \\ 0 & 4 \\ & 2 & 0 \\ & & \ddots & \ddots \end{bmatrix}}
        \only<3>{\sim\begin{bmatrix} 1 & -2 & & \\  & 1 & -3 & \\  & & \ddots & \ddots \\ 0 & 0 \\ & 2 & 0 \\ & & \ddots & \ddots \end{bmatrix}}
        \only<4>{\sim\begin{bmatrix} 1 & -2 & & \\  & 1 & -3 & \\  & & \ddots & \ddots \\ 0 & 0 \\ & 0 & 6 \\ & & \ddots & \ddots \end{bmatrix}}
        \only<5>{\sim\begin{bmatrix} 1 & -2 & & \\  & 1 & -3 & \\  & & \ddots & \ddots \\ 0 & 0 \\ & 0 &  0\\ & & \ddots & \ddots \end{bmatrix}}
    \end{align*}
    }

    \end{block}

\end{frame}

\subsection{Theory}

\begin{frame}{Theory}
    \only<1>{
    Tensor products are distributive
    \begin{align*}
        (u+\tilde{u})\otimes v & = u\otimes v+\tilde{u}\otimes v
        \\
        u\otimes (v+\tilde{v}) & = u\otimes v+u\otimes \tilde{v}\\
        (U\oplus \tilde{U})\otimes_R V & = U\otimes_R V\oplus\tilde{U}\otimes_R V
        \\
        U\otimes_R (V\oplus\tilde{V}) & = U\otimes_R V\oplus U\otimes \tilde{V}
    \end{align*}
    }
    \only<2>{
        Tensor products have a 1.
    \begin{align*}
        U\otimes_R R & \cong U & R\otimes_R V \cong V
    \end{align*}
    }
    \only<3>{
    Sometimes it is said tensor products are associative and commutative,
    \emph{that is nonsense}
    \begin{align*}
        \mathbb{R}^\otimes
    \end{align*}

    But in special cases, e.g.\ if $R$ is \emph{commutative}
    \begin{align*}
        U\otimes_R (V\otimes_R W) \cong (U\otimes_R V)\otimes_R W\\
        U\otimes_R V & \cong V\otimes_R U.
    \end{align*}

    But be warned $U_1\otimes \cdots\otimes U_n$ is generally not defined!
    }
\end{frame}

\begin{frame}{Universal Mapping Property}
    Further fact $ur\boxtimes v=(ur)v^{\dagger}=u(rv)^{\dagger}=u\boxtimes rv$;\\
    so $ur\otimes v=u\otimes r v$.

    \begin{block}{Theorem}
        If $*:U\times V\bmto W$ is distributive and $\forall r\in R$, $ur*v=u*rv$ then $\exists ! \hat{*}:U\otimes_R V\to W$ where
        \[
            u*v = \hat{*}(u\otimes v).
        \]
        In particular $U\otimes_R V$ does not depend on choice of presentations.
    \end{block}

\end{frame}

\begin{frame}{Whitney Tensor Product}

    Every module has its ``regular'' presentation
    \[ U_R=\Pres_R\langle e_u, u\in U \mid e_{u+\tilde{u}}=e_u+e_{\tilde{u}}, e_{ur}=e_u r\rangle
        \]
    \[ {_R V}=\Pres_R\langle e_v, v\in V\mid e_{v+\tilde{v}}=e_v+e_{\tilde{v}}, e_{rv}=re_v\rangle
        \]

    With these presentations we recover Whitney's definition (i.e. your textbook definition)
    \begin{align*}
        U\otimes_R V & =
        \left.
        R^{U\times V}\middle/
        \left\langle \begin{array}{c}
        e_{u+\tilde{u}}\otimes e_v=e_u\otimes e_v+e_{\tilde{u}}\otimes e_v,\\
        e_u\otimes e_{v+\tilde{v}}=e_u\otimes e_v+e_u\otimes e_{\tilde{v}},\\
        e_{ur}\otimes e_v=e_u\otimes e_{rv}
        \end{array}\right\rangle
        \right.
    \end{align*}
    So established methods are a special case.
\end{frame}

\begin{frame}
    Similar ideas picking up on matrix-vector product $R^{m\times n}\times R^n\bmto R^m$
    give rise to
    \[U\oslash V\times V\bmto U\]

    Which behave like fractions, e.g.\
    \[ A\oslash K\cong A\qquad A\to K\oslash (K\oslash A)\]

    \[A\oslash (B\otimes C)=A\oslash B\oslash C\]
    I.e.
    \[\hom(C\otimes B,A) \cong \hom(C,\hom(B,A))\]
\end{frame}

\section{Solving for Coordinates}

\begin{frame}

    \begin{block}{Applications}
        We \emph{have} a tensor.  Why would we want a tensor product?
    \end{block}

\end{frame}

\begin{frame}[fragile]
    What if $R=R_1\oplus R_2$?

    \centering
    \begin{tikzpicture}
        \node at (0,0) {\begin{tikzcd}
            (R_1\oplus R_2)^X\arrow[d,phantom,"\times"] \arrow[r,two heads]
                    & U_R=\Span X\arrow[d,phantom,"\times"]  \\
            (R_1\oplus R_2)^Y\arrow[d,"\boxtimes",tail] \arrow[r,two heads]
                    & {_R V}=\Span Y\arrow[d,"\otimes",tail] \\
            (R_1\oplus R_2)^{X\times Y} \arrow[r,two heads]
                     & U\otimes_{R_1\oplus R_2} V   \\
        \end{tikzcd}};
    \end{tikzpicture}
\end{frame}

\begin{frame}[fragile]
    What if $R=R_1\oplus R_2$?

    \centering
    \begin{tikzpicture}
        \node at (0,0) {\begin{tikzcd}
            R_1^X\oplus R_2^X\arrow[d,phantom,"\times"] \arrow[r,two heads]
                    & U_1\oplus U_2\arrow[d,phantom,"\times"]  \\
            R_1^Y\oplus R_2^Y\arrow[d,"\boxtimes",tail] \arrow[r,two heads]
                    & V_1\oplus V_2\arrow[d,"\otimes",tail] \\
            R_1^{X\times Y}\oplus R_2^{X\times Y} \arrow[r,two heads]
                     & (U_1\otimes_{R_1} V_1)\oplus (U_2\otimes_{R_2} V_2)   \\
        \end{tikzcd}};
    \end{tikzpicture}

    That's one of these:
    \pgfmathsetmacro{\xx}{0.5}
    \begin{tikzpicture}
			\pic at (\xx,-\xx,0) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (0,0,\xx) {shadedcube={\xx/\xx/\xx/gray/}};
			\pic at (0,\xx,0) {opencube={2*\xx/-2*\xx/2*\xx}};
		\end{tikzpicture}
    ...for which people are hunting!
\end{frame}

\begin{frame}[fragile]
    Solve for \textbf{universal} $R$!

    \centering
    \begin{tikzpicture}
        \node at (0,0) {\begin{tikzcd}
            (?)^X\arrow[d,phantom,"\times"] \arrow[r,two heads]
                    & U_?=\Span X\arrow[d,phantom,"\times"] \arrow[r,equal]
                        & U\arrow[d,phantom,"\times"] \\
            (?)^Y\arrow[d,"\boxtimes",tail] \arrow[r,two heads]
                    & {_? V}=\Span Y\arrow[d,"\otimes",tail] \arrow[r,equal]
                    & V\arrow[d,"*",tail]\\
            (?)^{X\times Y} \arrow[r,two heads]
                     & U\otimes_{?} V \arrow[r]
                        &  W\\
        \end{tikzcd}};
    \end{tikzpicture}

    Solution is the \textbf{Centroid}
    \[
        C(*)=\{(X,Y,Z)\mid Xu*v=Z(u*v)=u*(Yv)\}
    \]
\end{frame}

\begin{frame}{Cluster Algorithm (W. 2008)}
    $C(*)=\{(X,Y,Z)\mid  Xu*v=Z(u*v)=u*(Yv)\}$

    Random $\alpha\in C(*)$, \\
    if $\min_{\alpha}(x)=a(x) b(x)$ with $\deg a(x),\deg b(x)>0$ and
    \[1=\mathrm{GCD}(a(x),b(x))=s(x)a(x)+t(x)b(x)\]

    Then $e = s(\alpha )a(\alpha)$; $f=t(\alpha)b(\alpha)$\\
    Return $U=eU\oplus fU$, $V=eV\oplus fV$, $W=eW\oplus fW$.\\

    Else try another $\alpha$.

    \bigskip

    \textbf{Theorem W.} The resulting clusters are unique.

    %With constant number of trials you have decomposed or proven indecomposability.
\end{frame}

\begin{frame}
    Other observation:  Writing a product over larger coefficients makes for smaller
    dimensions.

    Isomorphism testing speeds up by orders of magnitude.
\end{frame}

% \begin{frame}[fragile]
%     General situation:
%     \[\Omega \to \End(U_1)\times\cdots\times \End(U_n)\]

%     \centering
%     \begin{tikzpicture}
%         \node at (0,0) {\begin{tikzcd}
%             \Omega|_1^X\arrow[d,phantom,"\times"] \arrow[r,two heads]
%                     & U_1=\Span X\arrow[d,phantom,"\times"]\\
%                    \vdots\arrow[d,phantom,"\times"] & \vdots\arrow[d,phantom,"\times"] \\
%             \Omega|_n^Y\arrow[d,"\boxtimes",tail] \arrow[r,two heads] \\
%                     & U_n\arrow[d,"(\cdots)",tail]\\
%             \Omega^{X\times Y} \arrow[r,two heads]
%                      & U_0\\
%         \end{tikzcd}};
%     \end{tikzpicture}
% \end{frame}

\begin{frame}{Wakeup Pure Algebra; you're directly useful!}
    For data science tensors use is still spartan.

    Different decompositions call for solving for different coordinate types,
    adjoints, nuclei, derivations, ...

    Such ideas essentially the same arose in
    \begin{itemize}
        \item Kaplansky and Jacobson non-associative algebras.
        \item Mal'cev and Miyasnikov on Groups of finite Morley Rank.
        \item Finite Simple groups, e.g.\ Parker-Norton MeatAxe and Schneider's work
        \item W. Direct and central product decomps. of $p$-groups.
    \end{itemize}

\end{frame}

\subsection{New Tensor Products}

\begin{frame}[fragile]
    Look back...did $R$ have to be a ring?
    \centering
    \begin{tikzpicture}
        \node at (0,0) {\begin{tikzcd}
            \Span S \arrow[d,phantom,"\times"]\arrow[r, hook]
                & R^X\arrow[d,phantom,"\times"] \arrow[r,two heads]
                    & U_R=\Span X\arrow[d,phantom,"\times"]  \\
            \Span T \arrow[r, hook]\arrow[d,"\boxtimes",tail]
                & R^Y\arrow[d,"\boxtimes",tail] \arrow[r,two heads]
                    & {_R V}=\Span Y\arrow[d,"\otimes",tail] \\
            R^X\boxtimes T+S\boxtimes R^Y \arrow[r, hook]
                 & R^{X\times Y} \arrow[r,two heads]
                     & U\otimes_R V   \\
        \end{tikzcd}};
    \end{tikzpicture}

    This quotient exists because we create a two-sided ideal.  No use
    of associative ring $R$.
\end{frame}

\begin{frame}[fragile]
    You can use \textbf{any non-associative algebra} $A$.

    Assume Lie, e.g. $[a,b]=ab-ba$ in a ring $R$.

    \centering
    \begin{tikzpicture}
        \node at (0,0) {\begin{tikzcd}
            \Span S \arrow[d,phantom,"\times"]\arrow[r, hook]
                & A^X\arrow[d,phantom,"\times"] \arrow[r,two heads]
                    & U_A=\Span X\arrow[d,phantom,"\times"]  \\
            \Span T \arrow[r, hook]\arrow[d,"\boxtimes",tail]
                & A^Y\arrow[d,"\boxtimes",tail] \arrow[r,two heads]
                    & {_A V}=\Span Y\arrow[d,"\otimes",tail] \\
            R^X\boxtimes T+S\boxtimes R^Y \arrow[r, hook]
                 & A^{X\times Y} \arrow[r,two heads]
                     & U\otimes_a V   \\
        \end{tikzcd}};
    \end{tikzpicture}

    With a lie algebra $ua\otimes v\neq u\otimes av$ but instead
    \[ [a,u\otimes v] = [a,u]\otimes v+u\otimes [a,v]\]
\end{frame}

\begin{frame}{Lie tensor products}
\only<1>{
    \begin{block}{Definability}
        Whitney tensor product $U_0\otimes_{R_1}\cdots \otimes_{R_n} U_n$ not
        generally well-defined (need bimodules or commutativity, i.e. constraints).

        Lie tensor product $\den{U_1,\ldots, U_n}_L$ exists for arbitrary numbers of modules.
    \end{block}
}
\only<2>{
    \begin{block}{Global reach}
        Whitney tensor product $U_0\otimes_{R_1}\cdots \otimes_{R_n} U_n$ (when defined)
        compares nearest neighbor relationships.

        Lie tensor product $\den{U_1,\ldots, U_n}_L$ compares all modules to all others.
    \end{block}
}
\only<3>{
    \begin{block}{Size}
        Whitney Tensor Product
        \[\dim U_0\otimes_{R_1}\cdots \otimes_{R_n} U_n\approx
        \frac{\dim U_1\cdots \dim U_n}{\dim R_1\cdots \dim R_n}\]

        Lie tensor product
        \[
            \dim \den{U_1,\ldots, U_n}_L
        \]
        given by subtle Clebsch-Gordan formulas, can actually be bounded by
        a constant while $\dim U_a$ go to infinity.
    \end{block}
}
\end{frame}

\begin{frame}{Universality of Derivation Tensors ``Densors''}

    \begin{block}{Theorem First-Maglione-W.}
        If a tensor $T$ factors through a tensor product over any nonassociative algebra $A$
        then $A$ then the tensor product $\otimes_A :U\times V\bmto U\otimes_A V$
        factors through the Lie tensor product over the derivations of $T$.
    \end{block}

    In formally the Lie tensor product over derivations is universal.

\end{frame}

\begin{frame}{Limits on Associativity}

    \begin{block}{Theorem FMW}
        Over fields with some nondegeneracy conditions.
        If $\Omega \subset \End(U_1)\times \cdots \times \End(U_n)$ is
        closed to composition then the operators in $\Omega$ are limited to nearest neighbor
        interactions governed by binomials
        \[X^{e_1}-X^{f_1},\ldots, X^{e_n}-X^{f_n}\]
        where the neighborhood is given by the support of $(e_i,f_i)$
    \end{block}

    \includegraphics[width=5in]{graphic.png}

\end{frame}

\end{document}