\documentclass[11pt]{article}
\usepackage{amsmath,amssymb,amsthm}
\usepackage{fullpage}
\usepackage[capitalise,nameinlink]{cleveref}
\usepackage{centernot}
\usepackage{tikz}
\usepackage{algpseudocode}
\usepackage{algorithm}
\usetikzlibrary{automata, positioning, arrows}
\crefname{lemma}{Lemma}{Lemmas}
\crefname{fact}{Fact}{Facts}
\crefname{theorem}{Theorem}{Theorems}
\crefname{corollary}{Corollary}{Corollaries}
\crefname{claim}{Claim}{Claims}
\crefname{example}{Example}{Examples}
\crefname{problem}{Problem}{Problems}
\crefname{setting}{Setting}{Settings}
\crefname{definition}{Definition}{Definitions}
\crefname{assumption}{Assumption}{Assumptions}
\crefname{subsection}{Subsection}{Subsections}
\crefname{section}{Section}{Sections}
\DeclareMathOperator*{\E}{\mathbb{E}}
\let\Pr\relax
\DeclareMathOperator*{\Pr}{\mathbb{P}}
\DeclareMathOperator*{\dist}{\mathrm{dist}}
\DeclareMathOperator*{\rev}{\mathrm{rev}}
\newcommand{\eps}{\varepsilon}
\newcommand{\inprod}[1]{\left\langle #1 \right\rangle}
\newcommand{\R}{\mathbb{R}}
\newcommand{\handout}[5]{
\noindent
\begin{center}
\framebox{
\vbox{
\hbox to 5.78in { {\bf CS 270: Combinatorial Algorithms and Data Structures
} \hfill #2 }
\vspace{4mm}
\hbox to 5.78in { {\Large \hfill #5 \hfill} }
\vspace{2mm}
\hbox to 5.78in { {\em #3 \hfill #4} }
}
}
\end{center}
\vspace*{4mm}
}
\newcommand{\lecture}[4]{\handout{#1}{#2}{#3}{Scribes: #4}{Lecture #1}}
\newtheorem{theorem}{Theorem}[section]
\newtheorem*{theorem*}{Theorem}
\newtheorem{itheorem}{Theorem}
\newtheorem{subclaim}{Claim}[theorem]
\newtheorem{proposition}[theorem]{Proposition}
\newtheorem*{proposition*}{Proposition}
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem*{lemma*}{Lemma}
\newtheorem{corollary}[theorem]{Corollary}
\newtheorem*{conjecture*}{Conjecture}
\newtheorem{fact}[theorem]{Fact}
\newtheorem*{fact*}{Fact}
\newtheorem{exercise}[theorem]{Exercise}
\newtheorem*{exercise*}{Exercise}
\newtheorem{hypothesis}[theorem]{Hypothesis}
\newtheorem*{hypothesis*}{Hypothesis}
\newtheorem{conjecture}[theorem]{Conjecture}
\theoremstyle{definition}
\newtheorem{definition}[theorem]{Definition}
\newtheorem{setting}[theorem]{Setting}
\newtheorem{construction}[theorem]{Construction}
\newtheorem{example}[theorem]{Example}
\newtheorem{question}[theorem]{Question}
\newtheorem{openquestion}[theorem]{Open Question}
% \newtheorem{algorithm}[theorem]{Algorithm}
\newtheorem{problem}[theorem]{Problem}
\newtheorem{protocol}[theorem]{Protocol}
\newtheorem{assumption}[theorem]{Assumption}
\newtheorem{exercise-easy}[theorem]{Exercise}
\newtheorem{exercise-med}[theorem]{Exercise}
\newtheorem{exercise-hard}[theorem]{Exercise$^\star$}
\newtheorem{claim}[theorem]{Claim}
\newtheorem*{claim*}{Claim}
\newtheorem{remark}[theorem]{Remark}
\newtheorem*{remark*}{Remark}
\newtheorem{observation}[theorem]{Observation}
\newtheorem*{observation*}{Observation}
% 1-inch margins, from fullpage.sty by H.Partl, Version 2, Dec. 15, 1988.
% \topmargin 0pt
% \advance \topmargin by -\headheight
% \advance \topmargin by -\headsep
% \textheight 8.9in
% \oddsidemargin 0pt
% \evensidemargin \oddsidemargin
% \marginparwidth 0.5in
% \textwidth 6.5in
% \parindent 0in
% \parskip 1.5ex
\begin{document}
\lecture{3 --- January 24, 2023}{Spring 2023}{Prof.\ Jelani Nelson}{Alejandro Sanchez and Sohom Paul}
\section{Overview}
In the last lecture we finished discussing the BNW algorithm for the single-source shortest paths problem. We ended the lecture by talking about how scaling can be used to speed up max flow algorithms like Ford-Fulkerson. We now continue our discussion of max flow algorithms by looking at a different approach, namely, blocking flows. We will use blocking flows to motivate link-cut trees, which we will discuss next lecture.
\section{Preliminaries}
Recall the statement of max $s-t$ flow:
\begin{definition}[Capacitated Graph]
A \emph{capacitated graph} is an unweighted directed graph $G = (V, E)$ equipped with a \emph{capacity function} $u: E \to \R$. Typically, we will have $u$ map into a finite set of positive integers $\lbrace 1, \ldots, U \rbrace$.
\end{definition}
\begin{definition}[Max Flow]
Given as input a capacitated graph $G = (V, E, u)$ and a pair of vertices $s, t \in V$, the \emph{maximum flow problem} is to compute some flow $f: E \to \R$ that maximizes the \emph{value} of the flow, given by $f^* = \sum_{e = (s, \cdot)} f_e$, subject to the following constraints:
\begin{itemize}
\item \textbf{Positivity:} $\forall e \in E, f_e \geq 0$
\item \textbf{Capacity:} $\forall e \in E, f_e \leq u_e$
\item \textbf{Conservation of Flow:} $\forall v \in V \setminus \lbrace s, t \rbrace, \sum_{e = (v, \cdot)} f_e = \sum_{e = (\cdot, v)} f_e$
\end{itemize}
A flow $f$ that satisfies the constraints but is not necessarily optimal is called a \emph{feasible} flow.
\end{definition}
Note that the optimization problem defining max flow has a linear objective and linear constraints, so it can be solved by a general-purpose linear program solver. However, faster solutions exist where we exploit the underlying graph structure of the problem.
In undergraduate algorithms, we have seen the Ford-Fulkerson algorithm for max flow, which works by repeatedly augmenting the flow in the residual graph until no more flow can be routed. We recall the definitions of these objects.
% TODO: Right now this isn't quite right, in that both (u, v) and (v, e) can be in E.
\begin{definition}[Residual Graph]
Given a flow $f$ on capacitated graph $G = (V, E, u)$, we define the \emph{residual graph} $G_f$ as a new capacitated graph $G_f = (V, E \cup \rev(E), u')$ (where $\textrm{rev}(E)$ denotes reversing all the edges). To compute $u'$, we initialize $u'_e = f_e$ for $e \in E$ and $0$ otherwise. Then, for each $e\in E$, we apply $u_e' \leftarrow u_e' - f_e$ and $u_{\rev(e)}' \leftarrow u_{\rev(e)}' + f_e$.
\end{definition}
\begin{definition}[Augmentation]
Given a flow $f_1$ in $G$ and a flow $f_2$ in the residual graph $G_{f_1}$, we \emph{augment} the first flow to give a new feasible flow on $G$ given by $f_1 + f_2$.
\end{definition}
\section{Historical Development of Max Flow Algorithms}
Broadly speaking, there are three classes of max-flow algorithms.
\begin{itemize}
\item \emph{pseudopolynomial} algorithms run in $\textrm{poly}(m, n, U)$ time\footnote{Note that $U$ takes $\log U$ bits to represent, so a $\textrm{poly}(U)$ factor is actually exponential in the input length.};
\item \emph{weakly polynomial} algorithms run in $\textrm{poly}(m, n, \log U)$ time
\item \emph{strongly polynomial} algorithms run in $\textrm{poly}(m, n)$ time\footnote{We work in the \emph{word RAM} model, which means given an input of $B$ bits we can perform memory access and arithmetic on words of size $O(\log B)$ in constant time. This means that we do not have to incur a $\log U$ runtime penalty just because the input values take $\log U$ bits to represent.}
\end{itemize}
Note that naive Ford-Fulkerson takes $O(m f^*) = O(mnU)$ time and is thus pseudopolynomial, while Ford-Fulkerson with scaling achieves $O(m^2 \log U)$ time and is thus weakly polynomial. Finally, Edmonds-Karp (which is variant of Ford-Fulkerson where we always search for $s-t$ paths in the residual graph using breadth-first search) takes only $O(m^2n)$ time and is thus strongly polynomial.
We have achieved the following runtimes for the max flow problem:
\begin{itemize}
\item strongly polynomial algorithms: \begin{itemize}
\item \cite{DBLP:conf/stoc/Orlin13} runs in $O(mn)$ time
\end{itemize}
\item weakly polynomial algorithms: \begin{itemize}
\item \cite{DBLP:journals/jacm/GoldbergR98} runs in $O(m \min\lbrace \sqrt{m}, n^{2/3} \rbrace \log(n^2/m) \log U)$ time
\item \cite{DBLP:conf/focs/LeeS14} runs in $\tilde{O}(m\sqrt{n} \log U)$ time
\item \cite{DBLP:conf/focs/ChenKLPGS22} runs in $m^{1 + o(1)} \log U$ time
\end{itemize}
\end{itemize}
In particular, the approaches of \cite{DBLP:conf/focs/LeeS14} and \cite{DBLP:conf/focs/ChenKLPGS22} make use of heavy continuous optimization machinery.
\section{Blocking Flows}
\subsection{Intuition}
Recall that in Ford-Fulkerson, we iterate the process of computing the residual graph with respect to the current flow, finding a flow within the residual graph, and augmenting to get a new flow. However, in Ford-Fulkerson, we always augment using only a path, which leads to our algorithm taking a large number of iterations in the worst case. Today, we will be able to speed things up by augmenting according to a \emph{blocking flow}.
\begin{definition}[Level Graph]
Given a residual graph $G_f$, the \emph{level graph} $L$ is the subgraph given by edges $(v, w)$ such that $\dist_{G_f}(s, w) = \dist_{G_f}(s, v) + 1$, where $\dist$ denotes the shortest path distance. We call the set of edges appearing in the level graph \emph{admissible}. An \emph{admissible path} is a path that only uses admissible edges.
\end{definition}
\begin{definition}[Blocking flow]
A \emph{blocking flow} $\tilde{f}$ in residual graph $G_f$ is one that only contains admissible edges and is such that every admissible $s-t$ path has at least one edge fully saturated by $\tilde{f}$.
\end{definition}
We show an example of a blocking flow in \cref{fig:blockingflowdiagram}. Note that blocking flows need not be max flows.
\begin{figure}[h!]
\centering
\begin{tikzpicture}[scale=0.2]
\tikzstyle{every node}+=[inner sep=0pt]
\draw [black] (38.3,-10.2) circle (3);
\draw (38.3,-10.2) node {$s$};
\draw [black] (25,-21.1) circle (3);
\draw [black] (50.2,-21.1) circle (3);
\draw [black] (25,-33.6) circle (3);
\draw [black] (50.2,-33.6) circle (3);
\draw [black] (38.3,-45.9) circle (3);
\draw (38.3,-45.9) node {$t$};
\draw [blue] (35.98,-12.1) -- (27.32,-19.2);
\fill [blue] (27.32,-19.2) -- (28.26,-19.08) -- (27.62,-18.3);
\draw (30.64,-15.16) node [above] {$1$};
\draw [black] (40.51,-12.23) -- (47.99,-19.07);
\fill [black] (47.99,-19.07) -- (47.74,-18.16) -- (47.06,-18.9);
\draw (45.26,-15.16) node [above] {$1$};
\draw [blue] (27.69,-22.43) -- (47.51,-32.27);
\fill [blue] (47.51,-32.27) -- (47.02,-31.46) -- (46.57,-32.36);
\draw (36.61,-27.85) node [below] {$1$};
\draw [black] (50.2,-24.1) -- (50.2,-30.6);
\fill [black] (50.2,-30.6) -- (50.7,-29.8) -- (49.7,-29.8);
\draw (49.7,-27.35) node [left] {$1$};
\draw [black] (25,-24.1) -- (25,-30.6);
\fill [black] (25,-30.6) -- (25.5,-29.8) -- (24.5,-29.8);
\draw (24.5,-27.35) node [left] {$1$};
\draw [black] (27.2,-35.64) -- (36.1,-43.86);
\fill [black] (36.1,-43.86) -- (35.85,-42.95) -- (35.17,-43.69);
\draw (30.63,-40.24) node [below] {$1$};
\draw [blue] (48.11,-35.76) -- (40.39,-43.74);
\fill [blue] (40.39,-43.74) -- (41.3,-43.52) -- (40.58,-42.82);
\draw (43.72,-38.28) node [left] {$1$};
\end{tikzpicture}
\caption{Vertices above are horizontally aligned according to their level. A blocking flow is highlighted in blue. Note that the blocking flow is not a max flow for this graph.}
\label{fig:blockingflowdiagram}
\end{figure}
\subsection{Monotonically Increasing $s-t$ Distance}\label{incdistance}
This is the main lemma we will need in the analysis of our blocking flow algorithms, as it will give us an upper bound to the number of iterations our algorithm will take.
\begin{lemma}
Let $G_f$ be some residual graph and $L$ be the associated level graph. Suppose we augment $f$ along some blocking flow. Then the new level graph $L'$ will be such that $\dist_{L'}(s, t) > \dist_L(s, t)$.
\end{lemma}
\begin{proof}
Define level $i$ to be the set of vertices at distance $i$ from $s$ in the \emph{original} graph $G_f$. Bear in mind that after we augment along our blocking flow, we will have a new residual graph $G_f'$, but we will still be referring to level sets according to their distance in $G_f$. Observe that $G_f$ contains some edges that go up exactly 1 level\footnote{By definition, these are the edges that comprise $L$.} and some edges that decrease or keep the level the same\footnote{Naturally, these are the edges in $G_f \setminus L$.}. Edges that go up more than one level do not exist. Finally, note that $s$ is in level $0$ and $t$ is in level $D := \dist_{L}(s, t)$.
When we augment along an admissible flow, we can potentially saturate edges in $L$ and introduce new reverse edges that go down from the current level, but we certainly cannot introduce new edges that go up levels as this would mean we pushed flow along an edge in $G_f\setminus L$, contradicting admissibility. It follows that $\dist_{L'}(s, t) \geq D$, as we need to follow at least $D$ edges in $L'$ in order to go from level $0$ to level $D$. Indeed, we also can conclude that equality cannot hold, because that would mean that every edge we followed has increased the level, implying we only used edges in $L$. This contradicts the assumption that we augmented along a blocking flow, as we could have simply pushed more flow along this path. \qedhere
% Then, when we augment an admissible flow, there are 3 types of edges in the new level graph $L'$:
% \begin{itemize}
% \item edges that originally belonged to $L$
% \item the reverse of edges that originally belonged to $L$ (because they received some flow pushed along them)
% \item edges that were originally in $G_f\setminus L$
% \end{itemize}
% Note that after we augment along an admissible flow, we will potentially saturate edges in $L$ and introduce new edges that go down levels in $L$, but we will certainly not introduce edges that skip across levels, as doing so would imply that we routed flow along edges not in $L$ and contradict admissibility. It follows, then, that $\dist_{L'}(s, t) \geq \dist_{L}(s, t)$.
% We note that equality holds only if we only use edges that were previously in $L$. Intuitively, this is because using any of the other types of edges means that you are not getting one step closer to $t$ with every step, so the shortest possible distance from $s$ to $t$ is achieved if we only use these types of edges. Now we note that if equality were to hold, then we would have some $s-t$ path in $L'$ that uses only edges that were previously in $L$. However, this would contradict the assumption that the flow we augmented along was blocking, as we could have pushed more flow before needing to construct $L'$ (namely along the path we just found). Thus we conclude that $\dist_{L'}(s, t) > \dist_L(s, t)$.
\end{proof}
Note that the maximum finite value $\dist_L (s, t)$ can be for a level graph associated with any flow is $n - 1$, as there cannot be a path with more than $n$ vertices in a graph. This means that we can increase $\dist_L(s, t)$ at most $O(n)$ times before we disconnect $s$ and $t$. Hence, all we need is to find an algorithm to compute a single blocking flow, and iterating it $O(n)$ times on successive residual graphs will give an algorithm to solve the max flow problem.
\subsection{Finding a Blocking Flow, Unit Capacity Case}\label{unitcapblockingflow}
For now, let us assume that our input graph has unit capacities (i.e.\ $u_e = 1$ for all $e$). We run an algorithm that is essentially a modified depth-first search on the level graph $L$ looking for admissable $s-t$ paths. When we arrive at vertex $v$, we take one of three operations:
\begin{enumerate}
\item \texttt{advance}: If there is a neighbor $w$ of $v$ such that $(v, w) \in L$, move to $w$. Store $\textrm{p}(w) \leftarrow v$ to maintain the current path.
\item \texttt{retreat}: If there are no admissible edges from $v$, go back to $\textrm{pred}(v)$ and remove the edge $(\textrm{pred}(v), v)$ from $L$.
\item \texttt{augment}: If we have reached $t$, then add 1 unit of flow to each edge in the $s-t$ path found, remove the path from $L$, and go back to $s$.
\end{enumerate}
\textbf{Warning:} The \texttt{augment} operation does \emph{not} compute the new residual graph $G_{f}'$; we wait until we have completed finding the blocking flow in order to do so.
In the algorithm above, we \texttt{advance} and \texttt{retreat} successively until we find an opportunity to \texttt{augment}. We do this iteratively until we have no more admissible paths from $s$ to $t$, which indicates that we have found a blocking flow for $L$. Once we have found a blocking flow for $L$, we reconstruct the new residual graph, $G_{f}'$. From $G_{f}'$, we construct its corresponding level graph $L$. This is summarized in \cref{alg:unitcap}
\begin{algorithm}
\caption{Max Flow Blocking Algorithm -- Unit Capacities}\label{alg:blk}
\begin{algorithmic}[1]
\Require $G$ -- a capacitated graph.
\State $G_f \gets G$
\Repeat
\State $L \gets LevelGraph(G_f)$
\Repeat
\State \textbf{augment} flow as much as possible in $L$
\Until{we find a blocking flow $\tilde{f}$}
\State $G_f \gets Residual(G_f, \tilde{f})$
\Until{there is no path from $s$ to $t$ in $G_f$}
\end{algorithmic}
\label{alg:unitcap}
\end{algorithm}
\subsubsection{Runtime analysis}
For our first analysis, we reiterate the fact that we need to find at most $O(n)$ blocking flows before we end up disconnecting $s$ and $t$. Therefore, the outer loop of Algorithm 1 runs at most $O(n)$ times. The overall runtime will depend on the time it takes to find a blocking flow.
\begin{claim}
Finding a blocking flow according to the algorithm specified in \cref{unitcapblockingflow} takes $O(m)$ time.
\end{claim}
\begin{proof}
Note that we can only \texttt{advance} along a given edge once, as it will either trigger a future \texttt{retreat} or \texttt{augment}. Thus we take $O(m)$ time across all calls to \texttt{advance}. Similarly, each edge contributes only $O(1)$ work to the total time spent \texttt{retreat}ing or \texttt{augment}ing, so those operations take $O(m)$ time as well. We conclude that finding a blocking flow can be done in $O(m)$ time for unit capacity graphs.
\end{proof}
Combining this algorithm with our outer loop as described in \cref{alg:unitcap} means that we have a $O(mn)$ runtime. However, using a different analysis gives us a different bound on the number of iterations, and therefore a more accurate overall runtime.
\begin{claim}
The overall runtime of \cref{alg:unitcap} is $O(m^{3/2})$.
\end{claim}
\begin{proof}
As the shortest path distance from $s$ to $t$ in $G_f$ increases each iteration, we deduce that after $d$ iterations the shortest $s-t$ path has at least $d$ edges. However, as the graph is unit capacity, then any max flow from $s$ to $t$ in $G_f$ can be written as a disjoint union of paths and cycles, as no edge can be routing flow for two different paths at once. Thus the total $s-t$ flow is upper bounded by the number of paths from $s$ to $t$, which is in turn upper bounded by $m/d$ as there are $m$ total edges. As each iteration of our algorithm will add at least $1$ unit of flow until termination, we conclude that there can be only $m/d$ further iterations before the algorithm terminates. Thus the total number of iterations is upper bounded by $\min_d (d + m/d) = O(\sqrt{m})$. This gives us an overall runtime of $O(m^{3/2})$.
\end{proof}
\subsection{Finding a Blocking Flow, General Case}
For the general case with non-unit capacities, we consider the same algorithm as in \cref{unitcapblockingflow}, but where \texttt{augment} will route as much flow as the path has capacity for.
\begin{claim}
With general capacities, the algorithm described above takes $O(mn)$ time to find a blocking flow.
\end{claim}
\begin{proof}
As before, we consider the total time spent performing each operation:
\begin{itemize}
\item \texttt{advance}: At some point in each sequence of \texttt{advance}s, we will either end up with a \texttt{retreat} or an \texttt{augment}. We can have at most $O(n)$ consecutive \texttt{advance}s (as there are no paths of length greater than $n$), and there are at most $O(m)$ \texttt{retreat}s and \texttt{augment}s (see below), so we spend at most $O(mn)$ time in \texttt{advance}.
\item \texttt{retreat}: We can only \texttt{retreat} across each edge once, so we spend at most $O(m)$ time in \texttt{retreat}.
\item \texttt{augment}: Every time we \texttt{augment}, at least one edge in that path gets fully saturated, so we remove that edge from the graph. Thus we can augment at most $m$ times. Each augment takes at most $O(n)$ time (from the path length), so spend at most $O(mn)$ time in \texttt{augment}. \qedhere
\end{itemize}
\end{proof}
As before, we note that there are $O(n)$ iterations so computing a max flow takes $O(mn^2)$ time in a general capacity graph.
\subsection{Link-Cut Trees Preview}
Note that \cref{alg:unitcap} may encounter the same vertex across multiple \texttt{advance}s, so it stands to reason that a clever choice of data structure would be able to memoize the $v-t$ paths. This forms the basis for link-cut trees.
\newpage
\bibliographystyle{alpha}
\newcommand{\etalchar}[1]{$^{#1}$}
\begin{thebibliography}{CKL{\etalchar{+}}22}
\bibitem[CKL{\etalchar{+}}22]{DBLP:conf/focs/ChenKLPGS22}
Li~Chen, Rasmus Kyng, Yang~P. Liu, Richard Peng, Maximilian~Probst Gutenberg,
and Sushant Sachdeva.
\newblock Maximum flow and minimum-cost flow in almost-linear time.
\newblock In {\em 63rd {IEEE} Annual Symposium on Foundations of Computer
Science, {FOCS} 2022, Denver, CO, USA, October 31 - November 3, 2022}, pages
612--623. {IEEE}, 2022.
\bibitem[GR98]{DBLP:journals/jacm/GoldbergR98}
Andrew~V. Goldberg and Satish Rao.
\newblock Beyond the flow decomposition barrier.
\newblock {\em J. {ACM}}, 45(5):783--797, 1998.
\bibitem[LS14]{DBLP:conf/focs/LeeS14}
Yin~Tat Lee and Aaron Sidford.
\newblock Path finding methods for linear programming: Solving linear programs
in {\~{o}}(vrank) iterations and faster algorithms for maximum flow.
\newblock In {\em 55th {IEEE} Annual Symposium on Foundations of Computer
Science, {FOCS} 2014, Philadelphia, PA, USA, October 18-21, 2014}, pages
424--433. {IEEE} Computer Society, 2014.
\bibitem[Orl13]{DBLP:conf/stoc/Orlin13}
James~B. Orlin.
\newblock Max flows in $o(nm)$ time, or better.
\newblock In Dan Boneh, Tim Roughgarden, and Joan Feigenbaum, editors, {\em
Symposium on Theory of Computing Conference, STOC'13, Palo Alto, CA, USA,
June 1-4, 2013}, pages 765--774. {ACM}, 2013.
\end{thebibliography}
\end{document}