% \iffalse meta-comment
%
% Copyright (C) 2014 by Alan Davidson
% ---------------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
% http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Alan Davidson.
%
% This work consists of the files logicproof.dtx and logicproof.ins
% and the derived filebase logicproof.sty.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{logicproof.dtx}
%
%\NeedsTeXFormat{LaTeX2e}
%\ProvidesPackage{logicproof}[2014/03/20 v1.0 Box proofs for propositional logic]
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{logicproof}[2014/03/20]
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
\DocInput{logicproof.dtx}
\PrintChanges
\PrintIndex
\end{document}
%
% \fi
%
% \CheckSum{0}
%
% \CharacterTable
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
% Digits \0\1\2\3\4\5\6\7\8\9
% Exclamation \! Double quote \" Hash (number) \#
% Dollar \$ Percent \% Ampersand \&
% Acute accent \' Left paren \( Right paren \)
% Asterisk \* Plus \+ Comma \,
% Minus \- Point \. Solidus \/
% Colon \: Semicolon \; Less than \<
% Equals \= Greater than \> Question mark \?
% Commercial at \@ Left bracket \[ Backslash \\
% Right bracket \] Circumflex \^ Underscore \_
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
%
% \changes{1.0}{2014/03/20}{First version for public release}
% \changes{0.1}{2004/12/05}{Initial version created}
% \GetFileInfo{logicproof.dtx}
%
% \DoNotIndex{\newcommand,\newenvironment}
%
% \providecommand*{\url}{\texttt}
% \title{The \textsf{logicproof} package}
% \author{Alan Davidson \\ \url{alan.davidson@gmail.com}}
% \date{20 March 2014}
%
% \maketitle
%
% \section{Introduction}
%
% This package provides support for Fitch-style box proofs, intended to be used
% for proofs in propositional logic and predicate logic. In this proof style,
% each statement of the proof is accompanied by a justification, and subproofs
% or lemmata within a larger proof are enclosed in boxes to separate them from
% the rest of the proof.
%
% \section{Usage}
%
% \DescribeEnv{logicproof}
% The |logicproof| environment takes a single argument, which should be a
% nonnegative integer describing the maximum number of nested subproofs that
% this proof will contain. Each line of the proof consists of two main
% columns: the proof statement of the current line, followed by an ampersand
% (|&|), followed by the justification for the statement.
% Lines should be separated from each other by a |\\|.
% The column of proof statements defaults to
% math mode, while the justification column defaults to normal text.
%
% If you add a |\label| within a proof, the corresponding |\ref| will be the
% current line number.
%
% \DescribeEnv{subproof}
% Within these logic proofs, it is often necessary to make subproofs which begin
% by making some sort of assumption that does not necessarily hold in the
% broader proof. To delineate the scope of these assumptions, use the |subproof|
% environment, which will draw a box around the statements of the proof for
% which these assumptions should hold. Subproofs can be nested within each
% other, up to the maximum level provided as an argument to the |logicproof|
% environment.
%
% Within a subproof, the format of each line is exactly the same as in the
% |logicproof| environment: a proof statement, followed by an ampersand (|&|),
% followed by a justification for the statement, with |\\| at the end of every
% line except the last one (which instead ends with |\end{subproof}|).
%
% If a statement has an empty justification, it is still important to put in the
% |&| to separate out the column in which the justification would go, or else
% the right sides of the subproof boxes will be misaligned for this statement.
%
% The previous line before a subproof begins should end in either |\\| or
% |\end{subproof}|.
%
% A warning for advanced \LaTeX~users: although most environments make their own
% groups (such that changes made within an environment go out of scope at the
% end of it), the |subproof| environment does not! Any changes made within a
% |subproof|
% environment will not go out of scope until the enclosing |logicproof|
% environment ends. This was done because groups cannot cross alignment tabs,
% but the |subproof| environment needs to use the same alignment as the
% enclosing |logicproof| environment does (or else they won't line up together).
% An inconvenient side effect of this is that when you forget to put in a
% |\end{subproof}|, the error message about mismatched environments points to
% the line number where the enclosing |logicproof| environment started, rather
% than the offending |subproof| environment.
%
% \section{Example}
%
% This example proves the validity of the sequent
% $(p\lor q)\lor r\vdash p\lor (q\lor r)$. There are many different styles that
% can be used for the justification of each step; we are using the style found
% in \emph{Logic in Computer Science: Modelling and Reasoning about Systems} by
% Huth and Ryan.
%
%\begin{verbatim}
%\begin{logicproof}{2}
% (p\lor q)\lor r & premise\\
% \begin{subproof}
% (p\lor q) & assumption\\
% \begin{subproof}
% p & assumption\\
% p\lor (q\lor r) & $\lor\mathrm{i}_1$, 3
% \end{subproof}
% \begin{subproof}
% q & assumption\\
% q\lor r & $\lor\mathrm{i}_1$, 5\\
% p\lor (q\lor r) & $\lor\mathrm{i}_2$, 6
% \end{subproof}
% p\lor (q\lor r) & $\lor$e, 2, 3--4, 5--7
% \end{subproof}
% \begin{subproof}
% r & assumption\\
% q\lor r & $\lor\mathrm{i}_2$, 9\\
% p\lor (q\lor r) & $\lor\mathrm{i}_2$, 10
% \end{subproof}
% p\lor (q\lor r) & $\lor$e, 1, 2--8, 9--11
%\end{logicproof}
%\end{verbatim}
% This compiles into the following:
%\begin{logicproof}{2}
% (p\lor q)\lor r & premise\\
% \begin{subproof}
% (p\lor q) & assumption\\
% \begin{subproof}
% p & assumption\\
% p\lor (q\lor r) & $\lor\mathrm{i}_1$, 3
% \end{subproof}
% \begin{subproof}
% q & assumption\\
% q\lor r & $\lor\mathrm{i}_1$, 5\\
% p\lor (q\lor r) & $\lor\mathrm{i}_2$, 6
% \end{subproof}
% p\lor (q\lor r) & $\lor$e, 2, 3--4, 5--7
% \end{subproof}
% \begin{subproof}
% r & assumption\\
% q\lor r & $\lor\mathrm{i}_2$, 9\\
% p\lor (q\lor r) & $\lor\mathrm{i}_2$, 10
% \end{subproof}
% p\lor (q\lor r) & $\lor$e, 1, 2--8, 9--11
%\end{logicproof}
%
% \section{Advanced Configuration}
%
% There are two lengths that can be configured manually if desired.
%
% \DescribeMacro{\subproofhorizspace}
% The
% horizontal distance between the sides of nested boxes is the length stored in
% |\subproofhorizspace|. If you have many nested subproofs, it might be
% desirable to make this space larger so that it is easier to distinguish
% between them.
%
% \DescribeMacro{\intersubproofvertspace}
% An extra vertical space of length
% |\intersubproofvertspace| is added after each statement in the proof. The
% intention here is to have this much space between consecutive subproofs. This
% is to say, when one subproof ends
% and the next subproof begins immediately, this is the distance between the
% bottom edge of the ending subproof and the top edge of the beginning subproof.
% This space is inserted after each line, however, so that the vertical spacing
% between them is consistent regardless of whether subproofs are begun or ended.
% If you want more compact proofs and you never use consecutive
% subproofs, it might be useful to reduce or remove this extra space.
%
% \section{Constraints}
% The environments in this package might not work properly if any of the
% following constraints are violated. These should not be difficult burdens;
% they are listed here mainly for completeness.
% \begin{itemize}
% \item Each proof and each subproof must be at least 1 statement long.
% \item Each subproof must start with at least 1 statement before containing
% another subproof inside itself. You should not have a subproof that
% immediately begins with a nested subproof.
% \item The end of each subproof must have at least 1 statement (or
% a new subproof) following
% it; a single proof statement cannot end multiple subproofs at once.
% Consequently, the last
% statement of the top-level proof must be outside of all subproofs. It is okay
% to immediately start a new subproof after ending a previous subproof.
% \end{itemize}
%
% \StopEventually{\PrintIndex\PrintChanges}
%
% \section{Summary of Implementation}
%
% The |logicproof| environment is built on the |tabular| environment. It has a
% column for the line number, a column for each possible nested subproof, a
% column for the statement, a column for the justification, and then a second
% column for each possible nested subproof.
% The columns corresponding to nested subproofs either contain a |\vline| if the
% subproof is currently being used, or nothing if the subproof is not being
% used.
% When a subproof is begun or ended, a |\cline| is used to draw
% horizontal lines between the columns corresponding to that subproof. In order
% to prevent multiple |\cline|'s from overlapping when one subproof is ended and
% another is immediately begun, each statement in the proof actually ends with
% a negative vertical space backing up to the previous line, then a space down
% |\intersubproofvertspace| and a redrawing of the subproof lines again to cover
% the extra space.
%
% \section{Implementation}
%
% \iffalse
%<*package>
% \fi
%
% \begin{macrocode}
\RequirePackage{array}
\RequirePackage{ifthen}
% \end{macrocode}
% \begin{macro}{\subproofhorizspace}
% \begin{macro}{\intersubproofvertspace}
% We allow the user to configure the horizontal and vertical distance between
% the edges of the boxes.
% \begin{macrocode}
\newlength{\subproofhorizspace}
\setlength{\subproofhorizspace}{0.5em}
\newlength{\intersubproofvertspace}
\setlength{\intersubproofvertspace}{0.333em}
% \end{macrocode}
% \end{macro}
% \end{macro}
% We use a variety of counters to keep track of the state.
% \begin{macrocode}
\newcounter{lp@line}% Current line number on the proof
\newcounter{lp@nested}% Number of nested subproofs we're currently in
\newcounter{lp@total@nests}% Maximum number of nested subproofs allowed
\newcounter{lp@cline@1}% Used to draw horizontal lines in subproofs
\newcounter{lp@cline@2}% Also used to draw horizontal lines in subproofs
\newcounter{lp@temp}% Temporary storage counter
% \end{macrocode}
%
% \begin{environment}{logicproof}
% Use this to make a logic proof. The argument it takes is the
% maximum number of nested subproofs you will use.
% \begin{macrocode}
\newenvironment{logicproof}[1]{%
\setcounter{lp@line}{0}%
\setcounter{lp@nested}{0}%
\setcounter{lp@total@nests}{#1}%
\setlength{\tabcolsep}{0mm}%
% \end{macrocode}
% When using the array package, the tabular environment contains the statement
% |\let\\\@arraycr| (note that with the array package, |\@tabularcr| is replaced
% with |\@arraycr| even within the tabular environment). So, to modify the
% behavior of |\\|, we're actually going to modify |\@arraycr|. Save a copy of the
% original definition first, so that we can use it inside our new definition.
% Remember that when the logicproof environment finishes, this redefinition
% will go out of scope and revert to the previous version, so we won't ruin
% any future uses of the tabular environment.
% \begin{macrocode}
\let\lp@orig@arraycr\@arraycr%
\renewcommand{\@arraycr}{\lp@cr}%
% \end{macrocode}
% Get labels to work in proofs by defining |\@currentlabel| to always be the
% line number, regardless of where we are in the proof. Note that the usual
% approach of using
% |\refstepcounter{lp@line}| doesn't work because it goes out of scope by the
% time we get to the next cell in the tabular environment.
% \begin{macrocode}
\renewcommand{\@currentlabel}{\p@lp@line\thelp@line}%
% \end{macrocode}
% If the maximum number of nested subproofs is 0, we need a slightly different
% column format, because the array environment doesn't like it when you repeat a
% formatting group 0 times.
% \begin{macrocode}
\ifthenelse{%
0=#1%
}{%
\def\lp@tab@format{{r@{~~~}>{$}l<{$}@{~~~~}l}}%
}{%
% \end{macrocode}
% Although we could use the |array| package's |>{...}| and |<{...}| features to
% have automatic placement of the vertical lines on the sides of subproofs,
% we would not be able to get the horizontal lines at the tops and bottoms
% of the subproofs to line up properly. Consequently, we go with the ``old
% school'' approach of putting subproofs in their own columns, so that we
% can use |\cline| to put the horizontal lines in their proper places.
% \begin{macrocode}
\def\lp@tab@format%
{{r@{~~~}*{#1}{l}@{~}>{$}l<{$}@{~~~~}l@{~}*{#1}{r}}}
}%
\center%
% \end{macrocode}
% We use the |tabular| environment instead of the |array| environment because
% we want
% to be able to have labels on individual lines. Since the entirety of the
% |array| environment is in math mode, it does not support more than one label
% per array.
% \begin{macrocode}
\expandafter\tabular\lp@tab@format%
\lp@start@proof@line%
}{%
\lp@stop@proof@line%
\endtabular%
\endcenter%
% \end{macrocode}
% To ensure that no one tries using the subproof environment outside of the
% logicproof environment, set the maximum number of nested subproofs to 0.
% \begin{macrocode}
\setcounter{lp@total@nests}{0}%
% \end{macrocode}
% Finally, make sure that all open subproofs have been closed. We do this last
% because if a subproof is still open, we need to set |\@currenvir| properly
% for |\end| to check and throw errors on, but previous commands have
% |\endgroup|'s that make it revert to previous definitions.
% \begin{macrocode}
\ifthenelse{%
0=\value{lp@nested}
}{% All is well.
}{% There are still open subproofs.
\def\@currenvir{subproof}%
}
}
% \end{macrocode}
% \end{environment}
% \begin{environment}{subproof}
% This environment puts a box around the lines of the proof within it. It
% should come right after either a |\\| or a |\end{subproof}|.
% \begin{macrocode}
\newenvironment{subproof}{%
% \end{macrocode}
% Make sure we don't start more nested subproofs than the current logicproof
% environment can handle.
% \begin{macrocode}
\ifthenelse{%
\value{lp@total@nests}>\value{lp@nested}%
}{% All is well; don't do anything.
}{%
\PackageError{logicproof}{Too many nested subproofs!}{%
Increase the maximum number of nested subproofs allowed
in the current logicproof environment.%
}%
}%
% \end{macrocode}
% The |\begin| and |\end| parts of an environment start and end a group, so that
% macros defined within them have local scope. However, a group cannot cross
% alignment tabs (|&|'s), which means that this subproof environment, which must
% cross them, needs to get rid of those extra groups first. So, we immediately
% end the group that |\begin| created before going on with the subproof. Note
% that this means any redefinitions of any macros we might have will persist
% outside this subproof and will not go out of scope until the entire
% logicproof environment is over. Note also that this approach is slightly
% brittle: if the implementation of |\begin| and |\end| ever changes, this
% subproof environment is likely to break.
% \begin{macrocode}
\endgroup%
\lp@stop@proof@line%
% \end{macrocode}
% Ideally, we'd use |\lp@extend@space| here. However, we first need to end the
% current line, which means putting in |\lp@orig@arraycr| and then going up an
% extra line in the tabular environment via |\lp@add@space|.
% \begin{macrocode}
\lp@orig@arraycr%
\lp@add@space%
\lp@go@up@a@line%
\stepcounter{lp@nested}%
\lp@cr@clines%
% \end{macrocode}
% The current line number was added in before this subproof was started. Do
% not add it in again now; just skip over the line number entry and go
% straight on to the subproof-drawing stuff.
% \begin{macrocode}
&%
\lp@continue@proof@line%
}{%
% \end{macrocode}
% If we try ending a subproof that has not yet begun, we will run into trouble
% with |\cline| trying to draw a horizontal line to a column past the end of the
% tabular environment. This happens before |\end| actually checks whether we're
% ending the right environment. In order to get a more useful error message,
% we first check that there is at least 1 open subproof.
% \begin{macrocode}
\ifthenelse{%
0<\value{lp@nested}%
}{% All is well; don't do anything.
}{%
\PackageError{logicproof}{Cannot end a subproof before it begins}{%
You must have a \protect\begin{subproof} before you can use %
\protect\end{subproof}.%
}%
}%
\lp@stop@proof@line%
\lp@cr@clines%
\addtocounter{lp@nested}{-1}%
\lp@extend@space%
\lp@start@proof@line%
% \end{macrocode}
% Now that we're done with the subproof, we need to create a group because
% |\end| is expecting us to still be in the group that was started in |\begin|. We
% also must redefine |\@currenvir| within that group, or the error-checking in
% |\end| will think we've ended the wrong environment (its previous redefinition
% went out of scope when we ended the group created by |\begin|).
% \begin{macrocode}
\begingroup%
\def\@currenvir{subproof}%
}
% \end{macrocode}
% \end{environment}
% \begin{macro}{\lp@cr}
% This is what the |\\| will be defined as inside the logicproof environment.
% \begin{macrocode}
\newcommand{\lp@cr}{%
\lp@stop@proof@line%
\lp@orig@arraycr%
\lp@extend@space%
\lp@start@proof@line%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@go@up@a@line}
% This moves up one entire line in the proof.
% \begin{macrocode}
\newcommand{\lp@go@up@a@line}{%
\vspace{-\ht\@arstrutbox}%
\vspace{-\dp\@arstrutbox}%
\vspace{-\intersubproofvertspace}%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@add@space}
% Extends the vertical lines at the sides of the proof down slightly, so that
% the horizontal lines at the end of the previous subproof and the start of the
% next one don't overlap. This basically inserts a blank row in the proof (no
% line number, no statement, no justification; just the subproof lines), then
% backs up part of a line.
% \begin{macrocode}
\newcommand{\lp@add@space}{%
\lp@extend@space%
% \end{macrocode}
% The |\@arstrutbox| is a box containing the minimum array height. Remember that
% the height of the strut is spread between the height above the baseline and
% the depth below it!
% \begin{macrocode}
\vspace{-\ht\@arstrutbox}%
\vspace{-\dp\@arstrutbox}%
% \end{macrocode}
% Uncommenting this would line things up exactly where they started.
% \begin{macrocode}
%\vspace{-\intersubproofvertspace}%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@extend@space}
% This extends the vertical lines at the sides of the subproofs down by
% an extra |\intersubproofvertspace.| This is done so that two subproofs in a
% row don't have their horizontal lines overlap each other.
% \begin{macrocode}
\newcommand{\lp@extend@space}{%
\vspace{-\ht\@arstrutbox}%
\vspace{-\dp\@arstrutbox}%
\vspace{\intersubproofvertspace}%
% \end{macrocode}
% Now, insert a row that has vertical lines for the subproofs but no line
% number, proof statement, or justification.
% \begin{macrocode}
&%
\lp@continue@proof@line%
&%
\lp@stop@proof@line%
\lp@orig@arraycr%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@amper}
% You can't have a |&| in a |\whiledo| loop, but this works instead.
% \begin{macrocode}
\newcommand{\lp@amper}{&}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@start@proof@line}
% This macro does everything on a proof line before the statement itself: it
% increments and prints the line number, then calls
% |\lp@continue@proof@line| to put in the vertical lines of any subproofs we're
% currently in.
% \begin{macrocode}
\newcommand{\lp@start@proof@line}{%
% \end{macrocode}
% We use |\stepcounter| instead of |\refstepcounter| here because the changes made
% by |\refstepcounter| to how labels get made would go out of scope by the time
% we got to the next cell of the tabular environment (i.e., 2 lines from
% here). Instead, we redefined |\@currentlabel| at the beginning of the
% environment to always contain the current value of the |lp@line| counter.
% \begin{macrocode}
\stepcounter{lp@line}%
\arabic{lp@line}.%
&%
\lp@continue@proof@line%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@continue@proof@line}
% This macro makes the vertical lines of the subproof boxes on the left side of
% the proof (i.e., the ones that come between the line numbers and the proof
% statements). We use |\lp@amper| here because the raw |&| token doesn't play
% well with |\whiledo| loops.
% \begin{macrocode}
\newcommand{\lp@continue@proof@line}{%
\setcounter{lp@temp}{0}%
\whiledo{\value{lp@temp}<\value{lp@nested}}{%
\vline%
\hspace*{\subproofhorizspace}%
\lp@amper%
\stepcounter{lp@temp}%
}%
\whiledo{\value{lp@temp}<\value{lp@total@nests}}{%
\hspace*{\subproofhorizspace}%
\lp@amper%
\stepcounter{lp@temp}%
}%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@stop@proof@line}
% This macro makes the vertical lines of the subproof boxes on the right side
% of the proof (i.e., the ones that come after the justifications for each
% step). It basically does the same thing as |\lp@continue@proof@line|, but in
% reverse order. We use |\lp@amper| here because the raw |&| token doesn't play
% well with |\whiledo| loops.
% \begin{macrocode}
\newcommand{\lp@stop@proof@line}{%
\whiledo{\value{lp@temp}>\value{lp@nested}}{%
\addtocounter{lp@temp}{-1}%
\lp@amper%
\hspace*{\subproofhorizspace}%
}%
\whiledo{\value{lp@temp}>0}{%
\addtocounter{lp@temp}{-1}%
\lp@amper%
\hspace*{\subproofhorizspace}%
\vline%
}%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@subtract@from@counter}
% Subtraction by a value in another counter is annoying, but with this we can
% use |\expandafter| and make it easier.
% \begin{macrocode}
\newcommand{\lp@subtract@from@counter}[2]{%
\addtocounter{#2}{-#1}%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@set@clines}
% This macro sets up where the horizontal bars go for subproofs.
% \begin{macrocode}
\newcommand{\lp@set@clines}{%
% \end{macrocode}
% |lp@cline@1 = lp@nested + 1|
% \begin{macrocode}
\setcounter{lp@cline@1}{\value{lp@nested}}%
\stepcounter{lp@cline@1}%
% \end{macrocode}
% |lp@cline@2 = 2 * lp@total@nests + 4 - lp@nested|
% \begin{macrocode}
\setcounter{lp@cline@2}{\value{lp@total@nests}}%
\addtocounter{lp@cline@2}{\value{lp@total@nests}}%
\addtocounter{lp@cline@2}{4}%
% \end{macrocode}
% Subtracting one counter from another is tricky. We need to expand the value
% of the counter being subtracted first.
% \begin{macrocode}
\expandafter\lp@subtract@from@counter\expandafter{%
\value{lp@nested}}{lp@cline@2}%
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\lp@cr@clines}
% This macro goes to the next line of the tabular environment and puts in a
% horizontal line for the beginning or end of the current subproof.
% \begin{macrocode}
\newcommand{\lp@cr@clines}{%
\lp@set@clines%
% \end{macrocode}
% We put the |\lp@orig@arraycr| here instead of in |\lp@stop@proof@line| because
% |\cline| doesn't seem to work properly unless it's right after the carriage
% return. Even moving it up above |\lp@set@clines| on the previous line messes
% it up.
% \begin{macrocode}
\lp@orig@arraycr%
\cline{\value{lp@cline@1}-\value{lp@cline@2}}%
}
% \end{macrocode}
% \end{macro}
%
% \iffalse
%
% \fi
%
% \Finale
\endinput