\documentclass[11pt,twoside]{scrartcl}

%opening
\newcommand{\lecid}{15-414}
\newcommand{\leccourse}{Bug Catching: Automated Program Verification}
\newcommand{\lecdate}{} %e.g. {October 21, 2013}
\newcommand{\lecnum}{8}
\newcommand{\lectitle}{Arrays with Updates}
\newcommand{\lecturer}{Matt Fredrikson}

\usepackage{lecnotes}

\usepackage[irlabel]{bugcatch}
\usepackage{xcolor}
\usepackage{listings}

\definecolor{mygray}{rgb}{0.5,0.5,0.5}
\definecolor{backgray}{gray}{0.95}
\lstdefinestyle{customjava}{
  belowcaptionskip=1\baselineskip,
  breaklines=true,
  language=Java,
  showstringspaces=false,
  numbers=left,
  xleftmargin=2em,
  framexleftmargin=1.5em,
  numbersep=5pt,
  numberstyle=\tiny\color{mygray},
  basicstyle=\footnotesize\ttfamily,
  keywordstyle=\color{blue},
  commentstyle=\itshape\color{purple!40!black},
  tabsize=2,
  backgroundcolor=\color{backgray},
  escapechar=\%
}


\begin{document}

\maketitle
\thispagestyle{empty}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Introduction}

In the previous lecture, we introduced arrays into the language. We modeled arrays as functions, and updated the semantics of terms to account for their behavior. We got plenty of practice using array terms in a proof, as we verified the functionality of the familiar binary search routine. Through a fairly lengthy derivation, we arrived at a suitable loop invariant, and proved its correctness.

This entire discussion was missing something crucial about arrays, namely that they can be updated as the program executes and subsequently read. In this lecture, we will continue defining the semantics of arrays, focusing on updates. We will introduce a notion of function updating that we will use to model array updates, and see that this allows us to avoid the tricky matter of aliasing to some extent. We will then introduce axioms to help us reason about programs that update arrays, and gain some further experience using the axioms on a non-trivial program.

%%%%%%%%%%%%%%%%%%%%

\section{Recall: Arrays as Functions}

Last lecture we introduced arrays into our language. Syntactically, this was not a huge change, and involved adding a new term for array lookup, as well as a new statement form for array assignment. However, in order to distinguish between variables that store constant values and those that store arrays, we need to assume that all variable symbols are already defined for either arrays or variables. Importantly, this means that there are new sorts of ill-formed terms, for example if $x$ is a variable symbol then $x(1)$ is not a valid term. Similarly, array symbols can only appear in indexed lookup terms, so if $a$ is an array symbol then $a$, $a+a$, $a<a$, \ldots are not valid terms.
\[
\begin{array}{llll}
%
\text{term syntax}
&
  \astrm,\bstrm ~\bebecomes&
  x &(\text{where}~x~\text{is a variable symbol}) \\
  && \alternative 
  c &(\text{where}~c~\text{is a constant literal}) \\
  && \alternative
  a(\astrm) &(\text{where}~a~\text{is an array symbol}) \\
  && \alternative
  \astrm+\bstrm & \\
  && \alternative
  \astrm\cdot\bstrm &
\\
\text{program syntax}
&
  \asprg,\bsprg ~\bebecomes&
  \pupdate{\pumod{x}{\astrm}}&(\text{where}~x~\text{is a variable symbol}) \\
  && \alternative
  \pupdate{\pumod{a(\astrm)}}{\bstrm}&(\text{where}~a~\text{is an array symbol}) \\
  && \alternative
  \ptest{\ivr} & \\
  && \alternative
  \pif{\ivr}{\asprg}{\bsprg} & \\
  && \alternative
  \asprg;\bsprg & \\
  && \alternative
  \pwhile{\ivr}{\asprg}
\end{array}
\]
Semantically, we modeled arrays as functions from their domain ($\mathbb{Z}$) to their range ($\mathbb{Z}$), which meant that the states of our programs are maps from the set of all variables to $\mathbb{Z} \cup (\mathbb{Z} \to \mathbb{Z})$. We then defined the semantics of terms with arrays in them.
\begin{definition}[Semantics of terms with basic arrays] The semantics of a term $\astrm$ in a state $\omega \in \mathcal{S}$ is its value $\omega\llbracket\astrm\rrbracket$, defined inductively as follows.
\begin{itemize}
\item $\omega\llbracket c \rrbracket = c$ for number literals $c$
\item $\omega\llbracket x \rrbracket = \omega(x)$
\item $\omega\llbracket a(\astrm) \rrbracket = \omega(a)(\omega\llbracket\astrm\rrbracket)$
\item $\omega\llbracket \astrm + \bstrm \rrbracket = \omega\llbracket \astrm\rrbracket + \omega\llbracket\bstrm \rrbracket$
\item $\omega\llbracket \astrm \cdot \bstrm \rrbracket = \omega\llbracket \astrm\rrbracket \cdot \omega\llbracket\bstrm \rrbracket$
\end{itemize}
\end{definition}

Today we'll continue defining the semantics of array updates, and of course see how to reason about programs that use this feature.

%%%%%%%%%%%%%%%%%%%%

\section{Array Updates}
\paragraph{Basic Arrays: Program Semantics.}
Now we move to the semantics of programs with arrays. We will need to add a new rule to the inductive definition that accounts for statements of the form $\llbracket\pupdate{\pumod{a(\astrm)}}{\bstrm}\rrbracket$, which update an array at a specified position. Operationally, this statement leaves the array $a$ unchanged except at the position given by the valuation of $\astrm$, which afterwards takes the valuation of $\bstrm$.

To specify this behavior, we introduce the \emph{function-patching} notation, which is defined as follows. If $A$ and $B$ are sets, and $f : A \to B$, then for $x,y \in X$ and $b \in B$ we write $\arrupd{f}{x}{b}$ as the function defined by:
\[
\arrupd{f}{x}{b}(y) =
\left\{
\begin{array}{ll}
b & \text{if}~x = y \\
f(y) & \text{otherwise}
\end{array}
\right.
\]
Intuitively, $\arrupd{f}{x}{d}$ simply updates $f$ at $x$ to the value $d$, leaving the rest of $f$ untouched. We can apply function patching multiple times, and the convention is to read the updates from right to left. So for example,
\[
\arrupd{\arrupd{\arrupd{f}{x}{1}}{y}{0}}{x}{2}(x) = 2
\]
The rightmost update is the one that is used on application, and any earlier updates are effectively dead.

\begin{definition}[Semantics of programs with basic arrays] \label{def:program-transition}
\indexn{\lenvelope\asprg\renvelope|textbf}%
Each program $\asprg$ is interpreted semantically as a binary reachability relation \m{\iaccess[\asprg]{\I}\subseteq\linterpretations{\Sigma}{V}\times\linterpretations{\Sigma}{V}} over states. The definition is idential to Definition 7 in Lecture 3, except on the following commands:
\begin{enumerate}
\item
\[
\llbracket\pupdate{\pumod{a(\astrm)}}{\bstrm}\rrbracket = 
\{(\omega,\nu) : \omega = \nu~\text{except}~\nu\llbracket a\rrbracket = \arrupd{\omega(a)}{\omega\llbracket\astrm\rrbracket}{\omega\llbracket\bstrm\rrbracket}\}
\]
\\
This is similar to the rule for simple assignment, but in the new state $a$ maps to a function that has been updated at the position given by $\omega\llbracket\astrm\rrbracket$ to take the value $\omega\llbracket\bstrm\rrbracket$. Intuitively, we update the target with an entirely new function, which happens to be the same as $\omega(a)$ everywhere except at $\omega\llbracket\astrm\rrbracket$.
\end{enumerate}
\end{definition}

\paragraph{Array Axioms.} 
We'd like to reason about programs that make full use of arrays, i.e., programs that update and subsequently read from arrays. The first two axioms, called the read-over-write axioms, have to do with reading from updated arrays.
\begin{center}
\begin{calculus}
\cinferenceRule[row1|$\text{row1}$]{readwrite-1}
{\linferenceRule[impl]
  {\astrm=\bstrm}
  {\arrupd{a}{\astrm}{e'}(\bstrm)=e'}
}{}%

\cinferenceRule[row2|$\text{row2}$]{readwrite-2}
{\linferenceRule[impl]
  {\astrm\ne\bstrm}
  {\arrupd{a}{\astrm}{e'}(\bstrm)=a(\bstrm)}
}{}%
\end{calculus}
\end{center}
The first read-over-write axiom, row1, establishes that a term that reads from the index that was most recently updated is equal to the value used in the update. The second, row2, establishes that a term that reads from an index that does not match that most recently updated is equal to the value at that index in the array before this update. Let's see how to use them in a proof.
\begin{sequentdeduction}
\linfer[allr] {
  \linfer[cut] {
    \linfer[orr] {
      \linfer[notr] {
        \linfer[id] {
          \lclose
        } {
          \lsequent{a(i) = x,i \ne j} {{}i \ne j,\arrupd{a}{i}{x}(j) = a(j)}
        }
      } {
        \lsequent{a(i) = x} {{}i = j,i \ne j,\arrupd{a}{i}{x}(j) = a(j)}
      }
    } {
      \lsequent{a(i) = x} {{}i = j \lor i \ne j,\arrupd{a}{i}{x}(j) = a(j)}
    }
    &\linfer[orl] {
      \textcircled{a}
    } {
      \lsequent{a(i) = x,i = j \lor i \ne j} {{}\arrupd{a}{i}{x}(j) = a(j)} 
    }
  } {
    \lsequent{a(i) = x} {{}\arrupd{a}{i}{x}(j) = a(j)} 
  }
} {
  \lsequent{a(i) = x} {{}\forall j . \arrupd{a}{i}{x}(j) = a(j)}
}
\end{sequentdeduction}
We continue with subtree \textcircled{a} below.
\begin{sequentdeduction}[array]
\linfer[orl] {
  \linfer[applyeql] {
    \linfer[row1] {
      \linfer[id] {
        \lclose
      } {
        \lsequent{a(i) = x,i = j} {{}x = a(i)} 
      }
    } {
      \lsequent{a(i) = x,i = j} {{}\arrupd{a}{i}{x}(i) = a(i)} 
    }
  } {
    \lsequent{a(i) = x,i = j} {{}\arrupd{a}{i}{x}(j) = a(j)} 
  }
  !\ \ \ \ \linfer[row2] {
    \lclose
  } {
    \lsequent{a(i) = x,i \ne j} {{}\arrupd{a}{i}{x}(j) = a(j)} 
  }
} {
  \lsequent{a(i) = x,i = j \lor i \ne j} {{}\arrupd{a}{i}{x}(j) = a(j)} 
}
\end{sequentdeduction}
In order to apply the axioms, we needed to use the cut rule to introduce the cases $i = j$, $i \ne j$ into our assumptions. This tactic is common in proofs involving array updates, as we need to consider whether the index being accessed has previously been updated.

Moving on to assignment statements, let's begin by reviewing the axiom for simple assignment of constants to variables.
\[
\cinferenceRule[assignb|$\dibox{:=}$]{assignment / substitution axiom}
{\linferenceRule[equiv]
  {p(\astrm)}
  {\axkey{\dbox{\pupdate{\umod{x}{\astrm}}}{p(x)}}}
}
{}
\]
The most natural thing to do is to simply extend this rule to array updates directly. Perhaps something like:
\[
\cinferenceRule[aassignbad|$\dibox{:=}_{()}$]{assignment / substitution axiom}
{\linferenceRule[equiv]
  {p(\bstrm)}
  {\axkey{\dbox{\pupdate{\umod{a(\astrm)}{\bstrm}}}{p(a(\astrm))}}}
}
{}
\]
Does this work? Let's try to use it on a simple formula.
\begin{sequentdeduction}[array]
\linfer[composeb] {
  \linfer[aassignbad] {
    \linfer[assignb] {
      \linfer[id] {
        \lclose
      } {
        \lsequent{a(j) \ne 5} {{}a(j)\ne 5}
      }
    } {
      \lsequent{a(j) \ne 5} {{}[i:=j]a(j)\ne 5}
    }
  } {
    \lsequent{a(j) \ne 5} {{}[i:=j][a(i):=5]a(j)\ne 5}
  }
} {
  \lsequent{a(j) \ne 5} {{}[i:=j;a(i):=5]a(j)\ne 5}
}
\end{sequentdeduction}
That doesn't seem right. We started assuming that $a(j)\ne 5$, and then assigned the element indexed by $j$ to take the value $5$, and ended up concluding that $a(j)$ still isn't 5! The problem that we've run into is one of aliasing: we can no longer use textual substitution to reason about updates, because the same object might be referenced by syntactically distinct terms. Indeed, when we write $a(i)$ on the right-hand side of an assignment, the assignment's target totally depends on the current state.

In short, we'll need a different axiom for array updates. Let's go back to our semantics, and consider how we modeled arrays. After an update, the new state is the same as the old one, except the variable $a$ maps to an updated version of the old array. This suggests that an axiom more along the lines of:
\[
\cinferenceRule[aassignb|$\dibox{:=}_{()}$]{assignment / substitution axiom}
{\linferenceRule[equiv]
  {p(\arrupd{a}{\astrm}{\bstrm})}
  {\axkey{\dbox{\pupdate{\umod{a(\astrm
  )}{\bstrm}}}{p(a)}}}
}
{}
\]
In other words, when we assign $a(i):=\astrm$, then we must show that $p$ holds when all free occurrences of $a$ are replaced by the patched function $\arrupd{a}{i}{\astrm}$. As a quick sanity check, let's make sure that this rule doesn't allow us to complete the proof from before.
\begin{sequentdeduction}[array]
\linfer[composeb] {
  \linfer[aassignbad] {
    \linfer[assignb] {
      \linfer[row1] {
        \lsequent{a(j) \ne 5} {{}5 \ne 5}
      } {
        \lsequent{a(j) \ne 5} {{}\arrupd{a}{j}{5}(j)\ne 5}
      }
    } {
      \lsequent{a(j) \ne 5} {{}[i:=j]\arrupd{a}{i}{5}(j)\ne 5}
    }
  } {
    \lsequent{a(j) \ne 5} {{}[i:=j][a(i):=5]a(j)\ne 5}
  }
} {
  \lsequent{a(j) \ne 5} {{}[i:=j;a(i):=5]a(j)\ne 5}
}
\end{sequentdeduction}
This is as we would hope, we can't prove that $5\ne5$. So, by modeling array updates with function patching, we have nicely sidestepped the tricky issue of aliasing. We haven't completely avoided it, as we still need to reason about the equality of array indexing terms, which will often require splitting a proof into cases. But accounting for it in this way ensures that we won't be able to continue with a proof unless we've introduced the relevant cases, and our reasoning will remain sound.

\paragraph{Using the axioms to prove reverse copy.}
Now let's use the axioms to prove a non-trivial formula, which asserts the correctness of a program that makes a reversed copy of an array in a second array. The postcondition that we want this program to satisfy is:
\[
\mathtt{eqrev}(a,b,n) \equiv \forall i . 0 \le i < n \rightarrow a(i) = b(n-i-1)
\]
The preconditions for such a method should be minimal. Basically, it would be nice to assume that the input array is defined between indices 0 and $n$, so $0 < n$. In the following proof, we will assume that the array $a$ is defined between 0 and $n-1$ inclusive, although this will not be explicit in our proof; for now, we can just take this fact for granted.
\[
\mathtt{pre} \equiv 0 < n
\]
Out of convenience, we will also add to our assumptions that our loop variable $i$ is initialized to 0, as this reduces the number of steps in the proof.
\begin{sequentdeduction}
\lsequent{0<n,i=0} {{}[\pwhile{i<n}\{{b(n-i-1) := a(i); i:=i+1}\}]\mathtt{eqrev}(a,b,n)}
\end{sequentdeduction}
Of course, the first question that we need to answer is what the loop invariant shall be. This is a fairly simple loop, so it shouldn't be too difficult to derive a suitable invariant by inspection. The loop starts from the beginning of $a$ and the end of $b$, and copies respective elements from $a$ to $b$. So on the $i$\textit{th} iteration, the last $i$ elements of $b$ match the first $i$ elements of $b$ in reverse order. This gives us:
\[
\inv \equiv \forall j . 0 \le j < i \rightarrow a(j) = b(n - j - 1)
\]
This bears close resemblance to our postcondition, as it should considering that the program does little else but establish this fact. Continuing with the proof,
\begin{sequentdeduction}
\linfer[loop] {
  \linfer {\textcircled{b}} {\lsequent{0<n,i=0} {{}\inv}}
  &\linfer {\textcircled{c}} {\lsequent{J,i<n} {{}[\alpha]J}}
  &\linfer {\textcircled{d}} {\lsequent{J,i\ge n} {{}\mathtt{eqrev}(a,b,n)}}
} {
  \lsequent{0<n,i=0} {{}[\pwhile{i<n}\{{b(n-i-1) := a(i); i:=i+1}\}]\mathtt{eqrev}(a,b,n)}
}
\end{sequentdeduction}
In the above, $\alpha$ corresponds to the loop body. Let's get \textcircled{b} out of the way.
\begin{sequentdeduction}[array]
\linfer[allr] {
  \linfer[implyr] {
    \linfer[andl] {
      \linfer[notl] {
        \linfer[applyeqr] {
          \linfer[id] {
            \lclose
          } {
            \lsequent{0<n,i=0,0\le j} {{}0\le j,a(j) = b(n - j - 1)}
          }
        } {
          \lsequent{0<n,i=0,0\le j} {{}i\le j,a(j) = b(n - j - 1)}
        }
      } {
        \lsequent{0<n,i=0,0\le j,j<i} {{}a(j) = b(n - j - 1)}
      }
    } {
      \lsequent{0<n,i=0,0\le j<i} {{}a(j) = b(n - j - 1)}
    }
  } {
    \lsequent{0<n,i=0} {{}0 \le j < i \rightarrow a(j) = b(n - j - 1)}
  }
} {
  \lsequent{0<n,i=0} {{}\forall j . 0 \le j < i \rightarrow a(j) = b(n - j - 1)}
}
\end{sequentdeduction}
Now let's check to make sure that the invariant we chose implies the postcondition, by doing \textcircled{d}.
\begin{sequentdeduction}[array]
\linfer[allr] {
  \linfer[alll] {
    \linfer[implyr] {
      \linfer[implyl] {
        \textcircled{e}
        !\textcircled{f}
      } {
        \lsequent{0 \le j < i \rightarrow a(j) = b(n - j - 1),i\ge n,0\le j<n} {{}a(j) = b(n-j-1)}
      }
    } {
      \lsequent{0 \le j < i \rightarrow a(j) = b(n - j - 1),i\ge n} {{}0 \le j < n \rightarrow a(j) = b(n-j-1)}
    }
  } {
    \lsequent{J,i\ge n} {{}0 \le j < n \rightarrow a(j) = b(n-j-1)}
  }
} {
  \lsequent{J,i\ge n} {{}\forall i . 0 \le i < n \rightarrow a(i) = b(n-i-1)}
}
\end{sequentdeduction}
The subtree \textcircled{e} follows from arithmetic, because we have $0 \le j$ in our assumptions, and $j < n \land n \le i \rightarrow j < i$:
\begin{sequentdeduction}
\linfer[qear] {
  \lclose
} {
  \lsequent{i\ge n,0\le j<n} {{}0\le j<i,a(j) = b(n-j-1)}
}
\end{sequentdeduction}
The subtree \textcircled{f} follows directly from identity, as we have $a(j) = b(n-j-1)$ in our assumptions:
\begin{sequentdeduction}
\linfer[id] {
  \lclose
} {
  \lsequent{a(j) = b(n - j - 1),i\ge n,0\le j<n} {{}a(j) = b(n-j-1)}
}
\end{sequentdeduction}
Great, our invariant gives us the precondition as we expected it would. Now for the final step of proving that the loop body preserves the invariant, which is the proof of \textcircled{c} above.
\begin{sequentdeduction}
\linfer[assignb] {
  \linfer[aassignb] {
    \linfer[allr] {
      \linfer[implyr] {
        \linfer[qear] {
          \linfer[alll] {
            \linfer {
              \textcircled{g}
            } {
              \lsequent{0 \le j < i \rightarrow a(j) = b(n - j - 1),i<n,0\le j\le i} {{}a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}
            }
          } {
            \lsequent{J,i<n,0\le j\le i} {{}a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}  
          }
        } {
          \lsequent{J,i<n,0\le j<i+1} {{}a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}
        }
      } {
        \lsequent{J,i<n} {{}0 \le j < i+1 \rightarrow a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}
      }
    } {
      \lsequent{J,i<n} {{}\forall j . 0 \le j < i+1 \rightarrow a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}
    }
  } {
    \lsequent{J,i<n} {{}[b(n-i-1) := a(i)]\forall j . 0 \le j < i+1 \rightarrow a(j) = b(n - j - 1)}
  }
} {
  \lsequent{J,i<n} {{}[b(n-i-1) := a(i); i:=i+1]\forall j . 0 \le j < i \rightarrow a(j) = b(n - j - 1)}
}
\end{sequentdeduction}
At this point it might be a good idea to pause and think about our next step. We have that $0 \le j \le i$, and an implication contingent on $0 \le j < i$. We can't prove this antecedent, but we can case split into $0 \le j < i$ and $j = i$. The former case will follow fairly directly, as we can apply the consequent of the implication to arrive at our goal. The latter case should be even more direct, as the equality $j=i$ will allow us to move forward with the read-over-write axioms. The following corresponds to \textcircled{g}, where in the following we use the following substitutions: 
\[
\begin{array}{lll}
%
\Gamma &\equiv& 0 \le j < i \rightarrow a(j) = b(n - j - 1),i<n,0\le j\le i \\
\Delta &\equiv& a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)
\end{array}
\]
We case split by cutting on $0 \le j < i \lor i = j$. This follows from arithmetic on the fact that $0 \le j \le i$. Now for \textcircled{g}:
\begin{sequentdeduction}
\linfer[cut] {
  \linfer[qear] {
    \lclose
  } {
    \lsequent{\Gamma} {{}0\le j<i\lor i=j,\Delta}
  }\ \ \ 
  &\linfer[orl] {
    \textcircled{h}
    &\textcircled{i}
  } {
    \lsequent{\Gamma,0\le j<i\lor i=j} {\Delta}
  }
} {
  \lsequent{\Gamma} {{}\Delta}
}
\end{sequentdeduction}
Now we've split into \textcircled{h} and \textcircled{i}, which correspond to the cases $0 \le j < i$ and $i = j$, respectively. Let's finish these off, starting with \textcircled{h} where we will omit $0 \le j \le i$ from our assumptions because we are adding $0 \le j < i$, which implies it:
\begin{sequentdeduction}
\linfer[implyl] {
  \textcircled{j}\ \ \ 
  &\linfer[cut] {
    \linfer[qear] {
      \lclose
    } {
      \lsequent{j<i} {{}i\ne j}
    }\ \ \ 
    &\linfer[row2] {
      \linfer[id] {
        \lclose
      } {
        \lsequent{a(j) = b(n - j - 1),j\ne i} {{}a(j) = b(n-j-1)}
      }
    } {
      \lsequent{a(j) = b(n - j - 1),j\ne i} {{}a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}
    }
  } {
    \lsequent{a(j) = b(n - j - 1),i<n,0\le j< i} {{}a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}
  }
} {
  \lsequent{0 \le j < i \rightarrow a(j) = b(n - j - 1),i<n,0\le j< i} {{}\Delta}
}
\end{sequentdeduction}
Subtree \textcircled{j} follows directly from our case premise, $0 \le i < j$. Note that our application of row2 took a very brief shortcut. To apply this rule, we needed to show that $n-j-1\ne n-i-1$. This follows directly from $i\ne j$, so we saved another cut by applying row2 directly from the premise $i\ne j$.

Now we move on to the final subtree \textcircled{i}:
\begin{sequentdeduction}
\linfer[applyeql] {
  \linfer[row1] {
    \linfer[qear] {
      \lclose
    } {
      \lsequent{i=j} {{}a(j) = a(j)}
    }
  } {
    \lsequent{i=j} {{}a(j) = \arrupd{b}{n-i-1}{a(j)}(n-i-1)}
  }
} {
  \lsequent{i=j} {{}a(j) = \arrupd{b}{n-i-1}{a(j)}(n-j-1)}
}
\end{sequentdeduction}

\end{document}