X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=article.tex;h=4cb6c96b79aa3fb9c5b7039feb222305a8e06ce6;hb=3bacd8e20d8b182ded5005470c0116ef99795ca9;hp=e8f44b514c2f188281bc8f0a4ad985d6c10377fc;hpb=e699df403adb72f770cc724de5e6e4128d576bb4;p=topbloke-formulae.git diff --git a/article.tex b/article.tex index e8f44b5..4cb6c96 100644 --- a/article.tex +++ b/article.tex @@ -1,16 +1,24 @@ -\documentclass[a4paper]{article} -\usepackage{MnSymbol} -\usepackage{stmaryrd} -\usepackage{slashed} +\documentclass[a4paper,leqno]{strayman} +\let\numberwithin=\notdef +\usepackage{amsmath} +\usepackage{mathabx} \usepackage{txfonts} -\begin{document} -\newcommand{\nothaspatch}{{% - \declareslashed{}{\sslash}{-0.04}{0}{\Sqsupset}\slashed{\Sqsupset}}} -\newcommand{\notinpatch}{{% - \declareslashed{}{\sslash}{-0.04}{0}{\Sqsubset}\slashed{\Sqsubset}}} -\newcommand{\haspatch}{\Sqsupset} -\newcommand{\inpatch}{\Sqsubset} +\usepackage{amsfonts} +\usepackage{mdwlist} +%\usepackage{accents} + +\renewcommand{\ge}{\geqslant} +\renewcommand{\le}{\leqslant} + +\newcommand{\has}{\sqsupseteq} +\newcommand{\isin}{\sqsubseteq} +\newcommand{\nothaspatch}{\mathrel{\,\not\!\not\relax\haspatch}} +\newcommand{\notpatchisin}{\mathrel{\,\not\!\not\relax\patchisin}} +\newcommand{\haspatch}{\sqSupset} +\newcommand{\patchisin}{\sqSubset} + +\newcommand{\set}[1]{\mathbb #1} \newcommand{\pa}[1]{\varmathbb #1} \newcommand{\pay}[1]{\pa{#1}^+} \newcommand{\pan}[1]{\pa{#1}^-} @@ -19,18 +27,215 @@ \newcommand{\py}{\pay{P}} \newcommand{\pn}{\pan{P}} -sponge -$ A \sqsubseteq B $ -$ A \not \sqsubseteq B $ -$ A \nsqsubseteq B $ -$ A \Sqsubset B $ -$ A \Sqsupset B $ -$ A \haspatch B $ -$ A \nothaspatch B $ -$ A \inpatch B $ -$ A \notinpatch B $ -$ A \nothaspatch \pa{C} $ -$ A \nothaspatch \py $ -$ A \nothaspatch \p_C^+ $ -$ A \nothaspatch \pan{C} $ +%\newcommand{\hasparents}{\underaccent{1}{>}} +%\newcommand{\hasparents}{{% +% \declareslashed{}{_{_1}}{0}{-0.8}{>}\slashed{>}}} +\newcommand{\hasparents}{>_{\mkern-7.0mu _1}} +\newcommand{\areparents}{<_{\mkern-14.0mu _1\mkern+5.0mu}} + +\renewcommand{\implies}{\Rightarrow} +\renewcommand{\equiv}{\Leftrightarrow} +\renewcommand{\land}{\wedge} +\renewcommand{\lor}{\vee} + +\newcommand{\pancs}{{\mathcal A}} +\newcommand{\pends}{{\mathcal E}} + +\newcommand{\pancsof}[2]{\pancs ( #1 , #2 ) } +\newcommand{\pendsof}[2]{\pends ( #1 , #2 ) } + +\newcommand{\patchof}[1]{{\mathcal P} ( #1 ) } +\newcommand{\baseof}[1]{{\mathcal B} ( #1 ) } + +\newcommand{\eqn}[2]{ #2 \tag*{\mbox{\bf #1}} } +\newcommand{\corrolary}[1]{ #1 \tag*{\mbox{\it Corrolary.}} } + +%\newcommand{\bigforall}{\mathop{\hbox{\huge$\forall$}}} +\newcommand{\bigforall}{% + \mathop{\mathchoice% + {\hbox{\huge$\forall$}}% + {\hbox{\Large$\forall$}}% + {\hbox{\normalsize$\forall$}}% + {\hbox{\scriptsize$\forall$}}}% +} + +\newcommand{\proof}[1]{{\it Proof.} #1 $\square$} + +\begin{document} + +\section{Notation} + +\begin{basedescript}{ +\desclabelwidth{5em} +\desclabelstyle{\nextlinelabel} +} +\item[ $ C \hasparents \set X $ ] +The parents of commit $C$ are exactly the set +$\set X$. + +\item[ $ C \ge D $ ] +$C$ is a descendant of $D$ in the git commit +graph. This is a partial order, namely the transitive closure of +$ D \in \set X $ where $ C \hasparents \set X $. + +\item[ $ C \has D $ ] +Informally, the tree at commit $C$ contains the change +made in commit $D$. Does not take account of deliberate reversions by +the user or reversion, rebasing or rewinding in +non-Topbloke-controlled branches. For merges and Topbloke-generated +anticommits or re-commits, the ``change made'' is only to be thought +of as any conflict resolution. This is not a partial order because it +is not transitive. + +\item[ $ \p, \py, \pn $ ] +A patch $\p$ consists of two sets of commits $\pn$ and $\py$, which +are respectively the base and tip git branches. $\p$ may be used +where the context requires a set, in which case the statement +is to be taken as applying to both $\py$ and $\pn$. +All these sets are distinct. Hence: + +\item[ $ \patchof{ C } $ ] +Either $\p$ s.t. $ C \in \p $, or $\bot$. +A function from commits to patches' sets $\p$. + +\item[ $ \pancsof{C}{\set P} $ ] +$ \{ A \; | \; A \le C \land A \in \set P \} $ +i.e. all the ancestors of $C$ +which are in $\set P$. + +\item[ $ \pendsof{C}{\set P} $ ] +$ \{ E \; | \; E \in \pancsof{C}{\set P} + \land \mathop{\not\exists}_{A \in \pancsof{C}{\set P}} + A \neq E \land E \le A \} $ +i.e. all $\le$-maximal commits in $\pancsof{C}{\set P}$. + +\item[ $ \baseof{C} $ ] +$ \pendsof{C}{\pn} = \{ \baseof{C} \} $ where $ C \in \py $. +A partial function from commits to commits. +See ``unique base'', below. + +\item[ $ C \haspatch \p $ ] +$\displaystyle \bigforall_{D \in \py} D \isin C \equiv D \le C $. +~ Informally, $C$ has the contents of $\p$. + +\item[ $ C \nothaspatch \p $ ] +$\displaystyle \bigforall_{D \in \py} D \not\isin C $. +~ Informally, $C$ has none of the contents of $\p$. + +Non-Topbloke commits are $\nothaspatch \p$ for all $\p$; if a Topbloke +patch is applied to a non-Topbloke branch and then bubbles back to +the Topbloke patch itself, we hope that git's merge algorithm will +DTRT or that the user will no longer care about the Topbloke patch. + +\end{basedescript} +\newpage +\section{Invariants} + +We maintain these each time we construct a new commit. \\ +\[ \eqn{No Replay:}{ + C \has D \implies C \ge D +}\] +\[\eqn{Unique Base:}{ + \bigforall_{C \in \py} \pendsof{C}{\pn} = \{ B \} +}\] +\[\eqn{Tip Contents:}{ + \bigforall_{C \in \py} D \isin C \equiv + { D \isin \baseof{C} \lor \atop + (D \in \py \land D \le C) } +}\] +\[\eqn{Base Acyclic:}{ + \bigforall_{B \in \pn} D \isin B \implies D \notin \py +}\] +\[\eqn{Coherence:}{ + \bigforall_{C,\p} C \haspatch \p \lor C \nothaspatch \p +}\] +\[\eqn{Foreign Inclusion:}{ + \bigforall_{D \text{ s.t. } \patchof{D} = \bot} D \isin C \equiv D \leq C +}\] + +\section{Some lemmas} + +\[ \eqn{Exclusive Tip Contents:}{ + \bigforall_{C \in \py} + \neg \Bigl[ D \isin \baseof{C} \land ( D \in \py \land D \le C ) + \Bigr] +}\] +Ie, the two limbs of the RHS of Tip Contents are mutually exclusive. + +\proof{ +Let $B = \baseof{C}$ in $D \isin \baseof{C}$. Now $B \in \pn$. +So by Base Acyclic $D \isin B \implies D \notin \py$. +} +\[ \corrolary{ + \bigforall_{C \in \py} D \isin C \equiv + \begin{cases} + D \in \py : & D \le C \\ + D \not\in \py : & D \isin \baseof{C} + \end{cases} +}\] + +\[ \eqn{Tip Self Inpatch:}{ + \bigforall_{C \in \py} C \haspatch \p +}\] +Ie, tip commits contain their own patch. + +\proof{ +Apply Exclusive Tip Contents to some $D \in \py$: +$ \bigforall_{C \in \py}\bigforall_{D \in \py} + D \isin C \equiv D \le C $ +} + +\[ \eqn{Exact Ancestors:}{ + \bigforall_{ C \hasparents \set{R} } + D \le C \equiv + ( \mathop{\hbox{\huge{$\vee$}}}_{R \in \set R} D \le R ) + \lor D = C +}\] + +\[ \eqn{Transitive Ancestors:}{ + \left[ \bigforall_{ E \in \pendsof{C}{\set P} } E \le M \right] \equiv + \left[ \bigforall_{ A \in \pancsof{C}{\set P} } A \le M \right] +}\] + +\proof{ +The implication from right to left is trivial because +$ \pends() \subset \pancs() $. +For the implication from left to right: +by the definition of $\mathcal E$, +for every such $A$, either $A \in \pends()$ which implies +$A \le M$ by the LHS directly, +or $\exists_{A' \in \pancs()} \; A' \neq A \land A \le A' $ +in which case we repeat for $A'$. Since there are finitely many +commits, this terminates with $A'' \in \pends()$, ie $A'' \le M$ +by the LHS. And $A \le A''$. +} + +\section{Commit annotation} + +We annotate each Topbloke commit $C$ with: +\begin{gather} +\tag*{} \patchof{C} \\ +\tag*{} \baseof{C}, \text{ if } C \in \py \\ +\tag*{} \bigforall_{\pa{Q}} + \text{ either } C \haspatch \pa{Q} \text{ or } C \nothaspatch \pa{Q} \\ +\tag*{} \bigforall_{\pay{Q} \not\ni C} \pendsof{C}{\pay{Q}} +\end{gather} + +We do not annotate $\pendsof{C}{\py}$ for $C \in \py$. Doing so would +make it wrong to make plain commits with git because the recorded $\pends$ +would have to be updated. The annotation is not needed because +$\forall_{\py \ni C} \; \pendsof{C}{\py} = \{C\}$. + +\section{Test more symbols} + +$ C \haspatch \p $ + +$ C \nothaspatch \p $ + +$ \p \patchisin C $ + +$ \p \notpatchisin C $ + +$ \{ B \} \areparents C $ + \end{document}