答案1
\leftskip
对来回工作进行了一些小的调整,以设置似乎在两列中显示的内容:
\documentclass{article}
\usepackage{algorithm,algpseudocode}
\usepackage{amsmath,eqparbox}
\begin{document}
\begin{algorithm}
\caption{Paxos}
\begin{algorithmic}[1]
\Statex \textbf{Client (Proposer)}
\vspace{-\baselineskip}
\addtolength{\leftskip}{.5\linewidth}%
\Statex \textbf{Server (Acceptor)}
\medskip
\addtolength{\leftskip}{-.5\linewidth}%
\Statex \textit{Initialization} \dotfill
\medskip
\Statex \eqmakebox[lbox][l]{$c$} \textit{$\triangleleft$ command to execute}
\Statex \eqmakebox[lbox][l]{$t = 0$} \textit{$\triangleleft$ ticket number to try}
\vspace{-2\baselineskip}
\addtolength{\leftskip}{.5\linewidth}%
\Statex \eqmakebox[rbox][l]{$T_{\text{max}} = 0$} \textit{$\triangleleft$ largest issued ticket}
\Statex
\Statex \eqmakebox[rbox][l]{$C = {\perp}$} \textit{$\triangleleft$ stored command}
\Statex \eqmakebox[rbox][l]{$T_{\text{store}} = 0$} \textit{$\triangleleft$ ticket used to store $C$}
\medskip
\addtolength{\leftskip}{-.5\linewidth}%
\Statex \textit{Phase 1} \dotfill
\medskip
\State $t = t + 1$
\State Ask all servers for ticket~$t$
\addtolength{\leftskip}{.5\linewidth}
\If{$t > T_{\text{max}}$}
\State $T_{\text{max}} = t$
\State Answer with $\texttt{ok}(T_{\text{store}}, C)$
\EndIf
\medskip
\addtolength{\leftskip}{-.5\linewidth}
\Statex \textit{Phase 2} \dotfill
\medskip
\If{a majority answers \texttt{ok}}
\State $\text{Pick}(T_{\text{store}}, C)$ with largest $T_{\text{store}}$
\If{$T_{\text{store}} > 0$}
\State $c = C$
\EndIf
\State Send $\texttt{propose}(t, c)$ to same majority
\EndIf
\addtolength{\leftskip}{.5\linewidth}
\If{$t = T_{\text{max}}$}
\State $C = c$
\State $T_{\text{store}} = t$
\State Answer \texttt{success}
\EndIf
\medskip
\addtolength{\leftskip}{-.5\linewidth}
\Statex \textit{Phase 3} \dotfill
\medskip
\If{a majority answers \texttt{success}}
\State Send $\texttt{execute}(c)$ to every server
\EndIf
\end{algorithmic}
\end{algorithm}
\end{document}
答案2
这是我的第二个更简单的解决方案。
一点历史:我最初认为在\vbox
es 中设置算法部分是一个简单的解决方案。但是,似乎我必须做一些技巧才能让algorithmicx
状态脱离框框。但我让它工作了。但我对复杂性不满意,所以我想到通过操纵缩进来改变它。不幸的是,我犯了一个愚蠢的错误,所以它没有 100% 工作(我以为这algorithmicx
曾经\ALG@tlm
缩进代码。但这是在之后的附加缩进\leftskip
。它有一些奇怪的副作用)。由于我没有更多时间,我发布了我的原始代码。回家后,我受到@Werner 解决方案的启发,并解决了它。基本上我只需要替换\ALG@tlm
就\leftskip
可以让它工作。我也在宏\rightskip
中进行了更改\Left
,以便左侧列不会溢出到右侧列中。我对宏使用了@Werner 的\vspace{-\baseline}
技巧\LeftRight
。
所以现在这里有解决方案,它基本上与@Werner 的一样,但使用了我在第一个解决方案中使用的宏。算法主体保持不变。只有宏发生了变化。
原始解决方案位于底部。
\documentclass{scrreprt}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{algorithm}
\usepackage{algpseudocode}
%%%% Macros for two column algorithms %%%%
\usepackage{calc}
\newlength{\halfwidth}
\newlength{\halfwidthplus}
\newcommand{\InitTwoCols}{%
\setlength{\halfwidth}{0.5\textwidth-1em}% separation left/right = 2em
\setlength{\halfwidthplus}{\textwidth-\halfwidth}%
}
% \Left{ALG} sets ALG in the left hand column
% This restricts the width of the column so that it doesn't overflow
% into the right hand column. If you want it to overflow, just leave out
% the \Left{} part.
\newcommand{\Left}[1]{%
\setlength{\rightskip}{\textwidth-\halfwidth}%
#1\par
\setlength{\rightskip}{0pt}%
}
% \Right{ALG} sets ALG in the right hand column
\newcommand{\Right}[1]{%
\addtolength{\leftskip}{\halfwidthplus}%
#1\par
\addtolength{\leftskip}{-\halfwidthplus}%
}
% \LeftRight sets two parts next to each other. It has n optional
% parameter indicating how many lines the left hand part occupies
% (default 1)
\newcommand{\LeftRight}[3][1]{\Left{#2}\vspace{-#1\baselineskip}\Right{#3}}
% \TwoHeads sets two headers, one above each column
\newcommand{\TwoHeads}[2]{%
\vskip2pt\LeftRight{\Statex \textbf{#1}}{\Statex \textbf{#2}}\vskip2pt}
% \Phase sets a text followed by dots across the full width
\newcommand{\Phase}[1]{\vskip2pt\Statex \emph{#1} \dotfill\par\vskip2pt}
% Redefine \Comment to use \triangleleft instead of \triangleright.
\algrenewcommand\algorithmiccomment[1]{\hfill$\triangleleft$ #1}%
\begin{document}
\begin{algorithm}
\caption{Paxos}
\begin{algorithmic}[1]
\InitTwoCols
\TwoHeads{Client (Proposer)}{Server (Acceptor)}
\Phase{Initialization}
\LeftRight{\Statex $c$ \Comment{command to execute}}{\Statex $T_{max} = 0$ \Comment{largest issued ticket}}
\Left{\Statex $t = 0$ \Comment{ticket number to try}}
\Right{\Statex $C = \bot$ \Comment{stored command}}
\Right{\Statex $T_{store} = 0$ \Comment{ticket used to store C}}
\Phase{Phase 1}
\Left{
\State $t = t + 1$
\State Ask all servers for ticket t
}
\Right{
\If {$t > T_{max}$}
\State $T_{max} = t$
\State Answer with ok($T_{store}, C$)
\EndIf
}
\Phase{Phase 2}
\Left{
\If {a majority answers ok}
\State Pick ($T_{store},C$) with largest $T_{store}$
\If {$T_{store} > 0$}
\State $c = C$
\EndIf
\State Send propose($t, c$) to same majority
\EndIf
}
\Right{
\If {$t = T_{max}$}
\State $C = c$
\State $T_{store} = t$
\State Answer success
\EndIf
}
\Phase {Phase 3}
\Left{
\If {a majority answers success}
\State Send execute($c$) to every server
\EndIf
}
\end{algorithmic}
\end{algorithm}
\end{document}
原解决方案:
我有一个基于包的解决方案algorithmicx
。然而,这个解决方案相当棘手。左右部分排版在框中,略小于一半\textwidth
。但由于algorithmicx
维护了有关算法状态的各种信息(例如块深度、哪种块处于活动状态、当前缩进),现在这些信息在框内更新,即一个组,因此在组的末尾,我们必须将这些信息从组中取出到周围的组中。我希望我已经涵盖了所有需要保留的信息。它看起来是这样的:
\documentclass{scrreprt}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{algorithm}
\usepackage{algpseudocode}
%%%% Code for two column algorithms %%%%
% This is done by typesetting the algorithm parts in a \vbox slightly
% less than half the \textwidth. However, this causes a problem:
% algorithmicx changes quite a number of "variables" while typesetting
% the algorithm. And when we leave the \vbox, by TeX's grouping
% mechanism, these are reset to the value they had when we entered the
% \vbox. There is one exception: counters, as these are global in LaTeX.
% So when we exit the \vbox, we have to take these values out of the
% box. We do this by copying them to globals at the end of the box, and
% then with \aftergroup we copy these globals back to the variables.
% I hope the following code covers all required variables.
% It would have beenm much easier if algorithmicx would have treated
% these "variables" as globals, which I think is possible.
\makeatletter
\newcommand{\globalsaveone}[2]{%
\expandafter\expandafter \expandafter\global \expandafter\expandafter \expandafter\let
\expandafter\expandafter \csname Global@#1@#2\endcsname \csname #1@#2\endcsname
}
\newcommand{\globalsave}[1]{%
\globalsaveone{#1}{0}%
\globalsaveone{#1}{1}%
\globalsaveone{#1}{2}%
\globalsaveone{#1}{3}%
\globalsaveone{#1}{4}%
}
\newcommand{\globalrestoreone}[2]{%
\expandafter\expandafter \expandafter\let \expandafter\expandafter \csname #1@#2\endcsname
\csname Global@#1@#2\endcsname
}
\newcommand{\globalrestore}[1]{%
\globalrestoreone{#1}{0}%
\globalrestoreone{#1}{1}%
\globalrestoreone{#1}{2}%
\globalrestoreone{#1}{3}%
\globalrestoreone{#1}{3}%
}
\newcommand{\substundefined}[1]{%
\ifx#1\@undefined UNDEF\else
\ifx#1\relax UNDEF\else#1\fi\fi
}
\newlength\Global@ALG@tlm
\newcommand{\restorecommand}{%
\ALG@tlm=\Global@ALG@tlm
\let\ALG@thisblock\Global@ALG@thisblock
\let\ALG@thislifetime\Global@ALG@thislifetime
\let\ALG@thisentity\Global@ALG@thisentity
\let\ALG@text\Global@ALG@text
\let\ALG@entitiecommand\Global@ALG@entitiecommand
\let\ALG@makebeginrepeat\Global@ALG@makebeginrepeat
\globalrestoreone{ALG@b@\ALG@L}{\substundefined\ALG@thisentity @\substundefined\ALG@thisblock}%
\globalrestore{ALG@currentblock}%
\globalrestore{ALG@currentlifetime}%
\globalrestore{ALG@ind}%
}
\newcommand{\restorealgorithminfo}{%
\global\Global@ALG@tlm=\ALG@tlm
\global\let\Global@ALG@thisblock\ALG@thisblock
\global\let\Global@ALG@thislifetime\ALG@thislifetime
\global\let\Global@ALG@thisentity\ALG@thisentity
\global\let\Global@ALG@text\ALG@text
\global\let\Global@ALG@entitiecommand\ALG@entitiecommand
\globalsaveone{ALG@b@\ALG@L}{\substundefined\ALG@thisentity @\substundefined\ALG@thisblock}%
\global\let\Global@ALG@makebeginrepeat\ALG@makebeginrepeat
\globalsave{ALG@currentblock}%
\globalsave{ALG@currentlifetime}%
\globalsave{ALG@ind}%
\aftergroup\restorecommand
}
\makeatother
%%% End of Restore part.
\usepackage{calc}
\newlength{\halfwidth}
\newlength{\halfwidthplus}
\newlength{\halfwidthmin}
\newcommand{\InitTwoCols}{%
\setlength{\halfwidth}{0.5\textwidth-1em-\leftmargin}%
\setlength{\halfwidthplus}{\textwidth-\halfwidth-\leftmargin}%
\setlength{\halfwidthmin}{\halfwidthplus-\halfwidth}%
}
\newcommand{\HalfBox}[1]{\vbox{%
\hsize=\halfwidth
\textwidth=\halfwidth
\linewidth=\halfwidth
\columnwidth=\halfwidth
#1%
\restorealgorithminfo
}%
}
% \Left sets the algorithm in the left hand half
% \Right sets the algorithm in the right hand half
% \LeftRight sets two parts next to each other
% \TwoHeads sets two headers, one above each half
% \Phase sets a text followed by dots across the full width
\newcommand{\Left}[1]{\noindent\HalfBox{#1}\par}
\newcommand{\Right}[1]{\noindent\hspace*{\halfwidthplus}\HalfBox{#1}\par}
\newcommand{\LeftRight}[2]{\noindent\HalfBox{#1}\hspace{\halfwidthmin}\HalfBox{#2}\par}
\newcommand{\TwoHeads}[2]{\vskip2pt\Statex \makebox[\halfwidthplus][l]{\textbf{#1}}\textbf{#2}\vskip2pt}
\newcommand{\Phase}[1]{\vskip2pt\Statex{\emph{#1} \dotfill}\par\vskip10pt}
\begin{document}
\begin{algorithm}
\caption{Paxos}
\begin{algorithmic}[1]
\InitTwoCols
\TwoHeads{Client (Proposer)}{Server (Acceptor)}
\Phase{Initialization}
\LeftRight{\Statex $c$ \Comment{command to execute}}{\Statex $T_{max} = 0$ \Comment{largest issued ticket}}
\Left{\Statex $t = 0$ \Comment{ticket number to try}}
\Right{\Statex $C = \bot$ \Comment{stored command}}
\Right{\Statex $T_{store} = 0$ \Comment{ticket used to store C}}
\Phase{Phase 1}
\Left{
\State $t = t + 1$
\State Ask all servers for ticket t
}
\Right{
\If {$t > T_{max}$}
\State $T_{max} = t$
\State Answer with ok($T_{store}, C$)
\EndIf
}
\Phase{Phase 2}
\Left{
\If {a majority answers ok}
\State Pick ($T_{store},C$) with largest $T_{store}$
\If {$T_{store} > 0$}
\State $c = C$
\EndIf
\State Send propose($t, c$) to same majority
\EndIf
}
\Right{
\If {$t = T_{max}$}
\State $C = c$
\State $T_{store} = t$
\State Answer success
\EndIf
}
\Phase {Phase 3}
\Left{
\If {a majority answers success}
\State Send execute($c$) to every server
\EndIf
}
\end{algorithmic}
\end{algorithm}
\end{document}
美学注解:$T_{max}$
当给出时,诸如 之类的东西看起来会好一些$T_{\mathit{max}}$
。