Previous chapters addressed the problem of robotic motion planning and control by leveraging techniques from control theory and optimal control. In particular, these techniques were used to generate open and closed-loop control laws to accomplish specific tasks such as trajectory generation, trajectory tracking, and stabilization or regulation about a particular robot state. One common component among all of these algorithms was the use of a model of the robot's kinematics or dynamics, which mathematically defines how the robot transitions from state to state based on control inputs.

In this chapter yet another set of algorithms for motion planning/trajectory generation is discussed\cite{LaValle2006}. These algorithms are particularly well suited for higher-level motion planning tasks, such as motion planning in environments with obstacles. This is accomplished by focusing on formulating the motion planning problem for a robot with respect to the robot's \textit{configuration space} rather than the \textit{state space} that was used in previous chapters. While the robot's configuration is derivable from its state (and still characterizes all of the robot's degrees of freedom), the definition of the configuration space can be useful because it can be tailored to collision avoidance tasks\footnote{In some cases the choice of configuration and state may end up being the same.}.
Historically speaking, these approaches were developed alongside many of the techniques from previous chapters, and are still being researched today.

\notessection{Search-Based Motion Planning}
Recall the general definition of the motion planning problem:
\begin{definition}[Motion planning problem]
Compute a sequence of actions to go from an initial condition to a terminal condition while respecting constraints and possibly optimizing a cost function.
\end{definition}
Previous chapters approached this problem by formulating mathematical optimization problems that minimized a cost function subject to constraints on the motion (i.e. from dynamics/kinematics, control limits, or conditions on the robot's state), or leveraged differential flatness properties of the model. In these approaches, the robot's trajectory was parameterized by its state $\x$ and the corresponding control inputs $\bu$ which satisfied a set of differential equations
\begin{equation*}
    \dot{\x} = f(\x, \bu).
\end{equation*}

In this chapter, the motion planning problem will instead be addressed with respect to a \textit{configuration space} ($C$-space).
The configuration $\q$ of a robot is derivable from the full dynamics state $\x$ and captures all of the degrees of freedom of the robot (i.e. all rigid body transformations). In some cases the state and configuration of the robot may be the same, but in other cases the definition of the configuration can be tailored to simplify the motion planning problem. One important example of this is for \textit{geometric path planning}, where paths in the configuration space can be planned without considering the robot kinematic/dynamics model.

\begin{example}[Motivating Example] \label{ex:mot}
\theoremstyle{definition}
Consider the L-shaped robot from Figure \ref{fig:2dworkspace} that lives in a 2D world with obstacles, and is trying to get from one point to another. Additionally, suppose this robot has a state $\x = [x,y,\theta,\dot{x}, \dot{y}, \dot{\theta}]^\top $, and consider a configuration space defined by $\q = [x,y,\theta]^\top $ which fully captures the robot's degrees of freedom. Since the motion planning problem in this case involves obstacle avoidance, it might be easier to just plan a sequence of configurations $\q$ that are collision free (as is shown in the right-side graphic of Figure \ref{fig:2dworkspace}).

In this case, the use of the configuration space has simplified the motion planning problem by abstracting away the consideration of the robot's dynamics. Once the geometric path has been defined in configuration space, other techniques (such as those discussed in previous chapters) could be used to perform lower-level control functions for path tracking.
\begin{figure*}[ht]
    \centering
    \includegraphics[width=0.85\linewidth]{tex/figs/ch05_figs/2d_ws_obstacles.png}
    \caption{Motivating example: motion planning in a 2D workspace with obstacles.}
    \label{fig:2dworkspace}
\end{figure*}

Additionally, it is important to note that the $C$-space is a subset of $\R^3$, and in particular the $C$-space is $\R^2 \times \mathcal{S}^1$. This subspace is special because it includes the \textit{manifold} $\mathcal{S}^1$, which characterizes the fact that the rotational degree of freedom $\theta$ satisfies $\theta = \theta \pm 2\pi k$ for all $k = 1,2,\dots$. This distinction is important to make because it endows the planner with the ability to move from one angle to another in two different ways (i.e. the robot can turn left or turn right). For example, suppose the robot in Figure \ref{fig:2dworkspace} has a current heading of $\theta_0$ and wants move to have a heading $\theta_g$ subject to the constraint of avoiding a $\C$-space obstacle (see Figure \ref{fig:rotational-dof-fig}). If the equivalence between the angles 0 and $2\pi$ is not established in the definition of the configuration space, the robot would not be able to traverse a collision-free path to the desired heading in the configuration space (see red trajectory). Instead, since the configuration space is defined with respect to $\Space^1$, the robot is able to achieve the desired heading (see green trajectory).

\begin{figure}[h]
\begin{center}
\includegraphics[width=0.9\textwidth]{tex/figs/ch05_figs/S1_obstacle.png}
\caption{Example trajectory planning where the description of the configuration space using the manifold $\Space^1$ is crucial to path planning. In particular, rotating clockwise leads to collision but rotating counter-clockwise is a feasible path.}
\label{fig:rotational-dof-fig}
\end{center}
\end{figure}

\end{example}

In this chapter two types of motion planning algorithms that plan in the configuration space will be discussed. The first class consists of \textit{grid-based methods}, and the second class consists of methods referred to as \textit{combinatorial planners}.

\subsection{Grid-based Motion Planners}
Suppose the robot's configuration $\q$ is a $d$ dimensional vector, then the $C$-space is a subset of $\R^d$. Critically, this is a continuous space and therefore there are an infinite number of potential configurations the robot could be in. To simplify this problem, grid-based motion planners use a grid to discretize the $C$-space into a finite number of allowable configurations. For example, in a simple $C$-space in two dimensions the grid might look like that shown in Figure \ref{fig:grid}.
\begin{figure}[ht]
    \centering
    \includegraphics[width=0.65\linewidth]{tex/figs/ch05_figs/2d_ws_grid.png}
    \caption{Discretizing the configuration space using a grid.}
    \label{fig:grid}
\end{figure}
In grid-based planners, undesirable configurations are simply represented by identifying some cells of the grid to be forbidden (e.g. for obstacle avoidance). The dynamics/kinematics of the robot are also abstracted away and it is assumed that the robot has the ability to move freely between adjacent cells (configurations).
After this discretization, the resulting motion planning problem is sometimes referred to as a \textit{discrete planning} problem because only a finite number of options are available at each step, and only a finite number of configurations are possible. The planning problem then reduces to finding a way to traverse through the cells from the initial configuration to a desired final configuration.

Mathematically, problems of this type are commonly expressed using discrete \textit{graphs}. A graph $G = (V,E)$, is simply defined by a set of vertices $V$ and a set of edges $E$. In the context of grid-based motion planners, each vertex $v \in V$ represents a \textit{free} cell of the grid, and each edge $(v,u) \in E$ corresponds to a connection between adjacent cells. With the graph representation, the planning problem is to find a way to traverse through the graph to reach the desired vertex. Algorithms for solving such problems are referred to as \textit{graph search methods}.

The advantages of such approaches are that they are simple and easy to use, and for some problems can be very fast. The disadvantages are primarily the result of the discretization procedure. In some cases, if the resolution of the grid is not fine enough the search algorithm may not always be able to find a solution. Additionally, for a fixed resolution the size of the graph grows exponentially with respect to the dimension of the configuration space. Therefore this approach is generally limited to simple robots with a low-dimensional configuration space.

\subsubsection{Label Correcting Algorithms}
Since the graph is defined by a \textit{finite} number of vertices (also referred to as \textit{nodes}) and edges, it should be theoretically possible to solve a graph search problem in finite time. However in order to achieve this in practice, several simple ``accounting'' tricks need to be used to keep track of how the search has progressed and to avoid redundant exploration. Additionally, it is desirable to find a ``best'' path, and so a mechanism for keeping track of the current best path is required during the search.

A general set of algorithms known as \textit{label correcting algorithms} employ such accounting techniques to guarantee good performance. In these algorithms, the notion of a ``best'' path is logged in terms of a cost-of-arrival.
\begin{definition}[Cost-of-Arrival]
The cost-of-arrival associated with a vertex $q$ with respect to a starting vertex $q_I$ is the cost associated with taking the best known route from $q_I$ to $q$ along edges of the graph, and is denoted $C(q)$.
\end{definition}
Additionally, in a slight abuse of notation the cost from traversing an edge from vertex $q$ to vertex $q'$ is denoted as $C(q,q')$. To keep track of what nodes have already been visited and which still need further exploration, label correcting algorithms define a set of \textit{frontier vertices} (sometimes also referred to as \textit{alive}). This allows guarantees to be made that the search algorithm will avoid redundant exploration, and will terminate in finite time. It also guarantees that if a path from the initial vertex $q_I$ to the goal vertex $q_G$ exists, that it will be found.

In general, label correcting algorithms take the following steps to find the best path from an initial vertex $q_I$ to a desired vertex $q_G$\footnote{In terms of robot motion planning this would be a search over paths through the discretized configuration space. Therefore the vertices of the graph are referred to as $q$ to better connect this abstraction with their physical interpretation being a particular robot configuration $\q$.}:

\begin{enumerate}
    \item Initialize the set of frontier vertices as $Q = \{q_I\}$ and set $C(q_I) = 0$. Initialize the cost-of-arrival of all other vertices $q'$ as $C(q') = \infty$.
    \item Remove a vertex from $Q$ and explore each of its connected vertices $q'$. For each $q'$, determine the candidate cost-of-arrival $\tilde{C}(q')$ associated with moving from $q$ to $q'$ as $\tilde{C}(q') = C(q) + C(q,q')$. If the candidate cost-of-arrival $\tilde{C}(q')$ is lower than the current cost-of-arrival $C(q')$ AND is lower than the current cost-of-arrival $C(q_G)$, then set $C(q') = \tilde{C}(q')$, define $q$ as the parent of $q'$, and add $q'$ to the set $Q$ if $q'$ is not $q_G$.
    \item Repeat step 2 until the set of frontier vertices $Q$ is empty.
\end{enumerate}

The bulk of the work is done is Step 2. In particular, for the selected $q$ from $Q$, these algorithms search its connected neighbors $q'$ to see if moving from $q$ to $q'$ will lead to a lower overall cost than previously found paths to $q'$. This is why the algorithms are called ``label correcting'', since they ``correct'' the cost-of-arrival as better paths are found throughout the search process. Eventually, once the best path from $q_I$ to $q$ is found, $q$ will never again be added to the set $Q$ and therefore the algorithm is guaranteed to eventually terminate.

\begin{theorem}[Label Correcting Algorithms]
If a feasible path exists from $q_I$ to $q_G$, then the label correcting algorithm will terminate in finite time with
$C(q_G)$ equal to the optimal cost of traversal, $C^*(q_G)$.
\end{theorem}

The primary way in which label correcting algorithms differ from each other is in how they select the next vertex $q$ from the set of frontier nodes $Q$. In fact, the set $Q$ is often referred to as a \textit{priority queue} since the algorithm might assign priority values to the order in which vertices are selected. Different approaches for prioritizing include \textit{depth-first search}, \textit{breadth-first search}, and \textit{best-first search}.

\paragraph{Depth-First Search}
Depth-first search in a directed graph expands each node up to the deepest level of the graph, until a chosen node has no more successors. Another way to think about this in terms of the set $Q$ is ``last in/first out'', where whenever a new vertex $q$ is selected from $Q$ it chooses those vertices that were most recently added.

\begin{marginfigure}
\begin{center}
\includegraphics[width=0.95\textwidth]{tex/figs/ch05_figs/depth_first.PNG}
\caption{Depth-First Search}
\end{center}
\end{marginfigure}

\paragraph{Breadth-First Search}
Breadth-first search begins with the start node and explores all of its neighboring nodes. Then for each of these nodes, it explores all their unexplored neighbors and so on. In terms of $Q$, this is like storing the frontier nodes as a queue with the first node added is the first node selected.

\begin{marginfigure}
\begin{center}
\includegraphics[width=0.95\textwidth]{tex/figs/ch05_figs/breadth_first.PNG}
\caption{Breadth First Search}
\end{center}
\end{marginfigure}

\paragraph{Best-First Search}
Also commonly known as \textit{Dijkstra’s algorithm}, this approach greedily selects vertices $q$ from $Q$ by looking at the current best cost-of-arrivals. Mathematically,
\begin{equation*}
   q = \textrm{arg} \min_{q \in Q} C(q).
\end{equation*}
This approach is sometimes considered an ``optimistic'' approach since it is essentially making the assumption that the best current action will always correspond to the best overall plan.
In practice this approach typically provides a more efficient search procedure relative to depth-first or breadth-first approaches because it can account for the cost of the path, however additional improvements can be made.

\subsubsection{A* Algorithm}
A* is a label correcting algorithm that is a modified version of Dijkstra's algorithm. In Dijkstra's algorithm the goal vertex $q_G$ is not taken into account, potentially leading to wasted effort in cases where the greedy choice makes no progress towards the goal. This is quantified by a quantity called the \textit{cost-to-go}.

\begin{definition}[Cost-to-Go]
The cost-to-go associated with a vertex $q$ with respect to a goal vertex $q_G$ is the cost associated with taking the best known route from $q$ to $q_G$ along edges of the graph.
\end{definition}
In practice, the cost-to-go is not usually known, and therefore \textit{heuristics} are used to provide approximate cost-to-go values $h(q)$. In order for the heuristic to be useful, it must be a positive \textit{underestimate} of the true cost-to-go. An example of a heuristic $h$ is to simply use distance to the goal.

While Djikstra's algorithm only prioritizes a vertex $q$ based on its cost-of-arrival $C(q)$, A* prioritizes based on cost-of-arrival $C(q)$ plus an approximate cost-to-go $h(q)$. This provides a better estimate of the total quality of a path than just using the cost-of-arrival alone. The A* algorithm is defined in Algorithm \ref{alg:astar}.
\begin{algorithm}[ht]\caption{A* Algorithm} \label{alg:astar}
	\KwData{$q_{I}$, $q_{G}$, $G$}
	\KwResult{path}
	$C(q) = \infty, \:\: f(q) = \infty, \:\:  \forall q$ \\
	$C(q_I) = 0$, $f(q_I) = h(q_I)$ \\
	$Q = \{q_I\}$ \\
	\While{$Q$ is not empty}{
	    $q = \argmin_{q' \in Q}f(q')$ \\
	    \If{$q = q_{G}$}{
	        \Return{path}
	    }
	    $Q$.remove($q$)\\
	    \For{$q' \in \{q' \: | \: (q,q') \in E\}$}{
	        $\tilde{C}(q') = C(q) + C(q,q')$ \\
	        \If{$\tilde{C}(q') < C(q')$}{
	        $q'$.parent = $q$\\
	        $C(q') = \tilde{C}(q')$\\
	        $f(q') = C(q') + h(q')$\\
	        \If{$q' \not\in Q$}{
	            $Q$.add($q'$) \\
	        }
	        }
	    }
	}
	\Return{failure}
\end{algorithm}
Note that in the case that the heuristic is chosen to be $h(q) = 0$ for all $q$ then A* is the same as Djikstra's algorithm.

\subsection{Combinatorial Motion Planning}
Combinatorial approaches to motion planning find paths through the continuous configuration space without resorting to discretizations like in grid-based planners. Recall that in grid-based planners, cells in the discretized configuration space that were undesirable were blocked out and simply not considered in the resulting path search. However, in the case of combinatorial planners the structure of the free portion of the configuration space is considered in a different way.

\begin{figure}[ht]
 \centering
 	\includegraphics[width=.5\textwidth]{tex/figs/ch05_figs/obs_padding.png}
	\caption{Free (white) and forbidden spaces (grey and red) of the configuration space for a simple circular robot in a 2D world. Note that the forbidden space accounts for the physical dimensions of the robot.}
 \label{fig:collision-free-space-fig}
\end{figure}
\begin{figure}[ht]
\begin{center}
\includegraphics[width=0.75\textwidth]{tex/figs/ch05_figs/2d_ws_Cfree.png}
\caption{Once the free (white) and forbidden (grey and red) configurations have been identified, the physical dimensions of the robot can be ignored. This figure shows an example of a path planning problem in $C$-space with obstacles.}
\label{fig:combinatorial-planning}
\end{center}
\end{figure}
First, the subset of the configuration space $C$ that is free (i.e. results in no collisions) is denoted as $C_{free}$ and is called the \textit{free space} (see Figures \ref{fig:collision-free-space-fig} and \ref{fig:combinatorial-planning}).
Combinatorial motion planning approaches operate by computing \textit{roadmaps} through the free space $C_{free}$. A roadmap is a graph $G$ where each vertex represents a point in $C_{free}$ and each edge represents a path through $C_{free}$ that connects a pair of vertices. The set $S$ is then defined for a particular roadmap graph $G$ as the set of all points in $C_{free}$ that are either vertices of $G$ or lie on any edge of $G$.
This graph structure is similar to that used in grid-based planners, with the important distinction that the vertices can potentially be \textit{any} configuration $q \in C_{free}$ while in grid-based planners the vertices are defined ahead of time by discretization. This distinction is very important because the flexibility of choosing the vertices does not result in any loss of information!
Once the roadmap has been defined, a path can be defined by first connecting the initial configuration $q_I$ and goal configuration $q_G$ to the roadmap and then solving a discrete graph search over the roadmap graph $G$.

In general combinatorial planners are \textit{complete} (i.e. the algorithm will either find a solution or will correctly report that no
solution exists), and can even be optimal in some cases. However, often times in practice they are not computationally feasible to implement except in problems with low-dimensional configuration spaces and/or simple geometric representations of the environment. Additionally, it requires that the free space be completely defined in advance, which is not necessarily a realistic requirement.

\subsubsection{Cell Decomposition}
One common approach for deriving the roadmap is to use \textit{cell decomposition} to decompose $C_{free}$.
Cell decomposition refers to the process of partitioning $C_{free}$ into a finite set of regions called cells, which should generally satisfy:
\begin{itemize}
    \item Each cell should be easy to traverse and ideally convex.
    \item Decomposition should be easy to compute.
    \item Adjacencies between cells should be straightforward to determine, in order to build the roadmap.
\end{itemize}

\begin{example}[2D Cell Decomposition] \label{ex:celldecomp}
Consider a two-dimensional configuration space as shown in Figure \ref{fig:cell-decompsition}. This space is decomposed into cells that are either lines or trapezoids by a process called vertical cell decomposition. Once the cells have been defined, the roadmap is generated by placing a vertex in each cell (e.g. at the centroid) as well as a vertex on each shared edge between cells.

If the forbidden space is polygonal, cell decomposition methods work pretty well and each cell can be made to be convex. In general, there exist several approaches for performing cell decomposition. However, cell decomposition in higher dimensions becomes increasingly challenging.

\begin{figure}[ht]
\begin{center}
\includegraphics[width=0.74\textwidth]{tex/figs/ch05_figs/2d_cell_decomp.png}
\caption{Example of 2D Cell Decomposition with $C_{free}$ colored white. A roadmap is defined as the graph $G$ with vertices shown as black dots and edges connecting them. To solve a planning problem with $q_{start}$ and $q_{goal}$ these points are first connected to the roadmap, and then the path is easily defined.}
\label{fig:cell-decompsition}
\end{center}
\end{figure}
\end{example}

\subsubsection{Other Roadmaps}
Other ways to define roadmaps besides using cell decomposition exist. Two possible examples include a maximum clearance or minimum distance approach. Maximum clearance roadmaps simply try to always keep as far from obstacles as possible, for example by following the centerline of corridors. These roadmaps are also sometimes referred to as ``generalized Voronoi diagrams''. Minimum distance roadmaps are generally the exact opposite of maximum clearance roadmaps in that they tend to graze the corners of the forbidden space. In practice this is likely not desirable and therefore these approaches are less commonly used (without modification).

\subsection{Exercises}
\subsubsection{A* Motion Planning}
Complete \textit{Problem 1: A* Motion Planning} located in the online repository:

\vspace{\baselineskip}

\url{https://github.com/PrinciplesofRobotAutonomy/AA274A_HW2},

\vspace{\baselineskip}

where you will implement the A* grid-based motion planning algorithm for some simple 2D environments.


\section{Preliminaries}

\begin{itemize}
    \item Define homology groups
    \item Define the fundamental group
\end{itemize}

The Poincaré conjecture very roughly states that every 3-dimensional shape that has no holes, has a defined inside and outside and no boundary, must be the 3-dimensional sphere.
It is a bit more complicated than this, but this is essentially the statement.
So what is a 3-dimensional shape, and how can we describe these properties that we mentioned using proper mathematics?

Let's start with shapes.
In mathematics, and in particular the field of topology, shapes are described by manifolds.
An $n$-dimensional manifold is a shape that looks locally like $n$-dimensional Euclidean space.
An example is the surface of the earth.
It is locally flat, meaning that the area you see around you looks a bit like just a flat plane, i.e. 2-dimensional Euclidean space.
There might be some bumps and cavities, but these can be ignored.

\begin{definition}
An $n$-dimensional manifold is a (second countable Hausdorff) topological space $M$ such that for every point $p\in M$, there is an open neighborhood $U$ of $p$ and a homeomorphism $\phi:U\longrightarrow V$, where $V$ is an open set in $\R^n$.
\end{definition}

Here a homeomorphism means that $\phi$ is a continuous isomorphism where its inverse is also continuous.

The next thing we need is the notion of homology.
I will not cover homology in full detail here.
It is a really important gadget, but it takes time to cover it properly.
That said I have added the definition below.

\begin{definition}
Let $M$ be a manifold.
We define the n'th singular homology group of $M$ to be the quotient

$$H_n(M) = \frac{Z_n(M)}{B_n(M)} = \frac{Ker(\partial_n)}{Im(\partial_{n+1})},$$

where $Z_n(M)$ is the group of $n$-cycles and $B_n(X)$ is the group of $n$-boundaries.
\end{definition}


% Template Source: https://www.overleaf.com/latex/templates/math-notes-and-homeworks-template/pqpxbnjjdtcs

\documentclass[12pt]{article}

\usepackage[margin=1in]{geometry}
\usepackage{amsmath,amsthm,amssymb,graphicx,mathtools,tikz,hyperref}
\usetikzlibrary{positioning}
\newcommand{\n}{\mathbb{N}}
\newcommand{\z}{\mathbb{Z}}
\newcommand{\q}{\mathbb{Q}}
\newcommand{\cx}{\mathbb{C}}
\newcommand{\real}{\mathbb{R}}
\newcommand{\field}{\mathbb{F}}
\newcommand{\ita}[1]{\textit{#1}}
\newcommand{\com}[2]{#1\backslash#2}
\newcommand{\oneton}{\{1,2,3,...,n\}}
\newcommand\idea[1]{\begin{gather*}#1\end{gather*}}
\newcommand\ef{\ita{f} }
\newcommand\eff{\ita{f}}
\newcommand\proofs[1]{\begin{proof}#1\end{proof}}
\newcommand\inv[1]{#1^{-1}}
\newcommand\setb[1]{\{#1\}}
\newcommand\en{\ita{n }}
\newcommand{\vbrack}[1]{\langle #1\rangle}

\newenvironment{definition}[2][Definition]{\begin{trivlist}
\item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}}
\newenvironment{theorem}[2][Theorem]{\begin{trivlist}
\item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}}
\newenvironment{lemma}[2][Lemma]{\begin{trivlist}
\item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}}
\newenvironment{exercise}[2][Exercise]{\begin{trivlist}
\item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}}
\newenvironment{remark}[2][Remark]{\begin{trivlist}
\item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}}
\newenvironment{proposition}[2][Proposition]{\begin{trivlist}
\item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}}
\newenvironment{corollary}[2][Corollary]{\begin{trivlist}
\item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}}
 \hypersetup{
 colorlinks,
 linkcolor=blue
 }
\begin{document}
\date{}

\title{Topology II}
\author{Jose Iovino\\Professor \\UTSA}

\maketitle
\section{Filters}
\subsection{Basic Notions}
Topology is the study of limits and convergence.  Filters are important because they generalize the notion of limit.  Intuitively, a filter is collection of ``large" sets.  Let $I$ be a set.  We claim a subset of $I$ is ``large" if it contains ``almost all" of the elements of $I$.

Conditions that ``large" subsets must satisfy.
\begin{itemize}
  \item $I$ is a large subset of itself, since it contains ``all" of the elements.
  \item An intersection of large subsets should be large.
  \item If $A$ is a large subset of $I$, then any $B \supseteq A$ is large.
\end{itemize}

\begin{definition}{filter}
Let $I$ be any set.  A filter $\mathcal{F}$ on $I$ is a collection of subsets of $I$ such that
\begin{enumerate}
    \item $I \in \mathcal{F}$ and $\emptyset \not\in \mathcal{F}$.
    \item If $A, B \in \mathcal{F}$, then $A \cap B \in \mathcal{F}$.
    \item If $A \in \mathcal{F}$ and $B \supseteq A$, then $B \in \mathcal{F}$.
\end{enumerate}
\end{definition}

The universal quantifier ``$\forall$" says a property holds for all elements, while the existential quantifier ``$\exists$" says a property holds for at least element.  Filters enable the definition of quantifiers between these two extremes which capture the notion of a property holding for ``almost all" elements.

\begin{definition}{almost all}
If $\mathcal{F}$ is a filter on $I$ and $P$ is a property.  We say that almost all elements of $I$ satisfy $P$ when
\[
\{ x \in I | x \textrm{ satisfies } P\} \in \mathcal{F}.
\]
\end{definition}

\subsection{Examples}
\subsubsection{Co-finite Filter on $\mathbb{N}$}
On $\mathbb{N}$, let
\[\mathcal{F} = \{A \subset \mathbb{N} | A^c \textrm{ is finite} \}.
\]
This is the co-finite filter.  Check that it is indeed a filter.

\begin{enumerate}
    \item $\mathbb{N} \in \mathcal{F}$ because $\mathbb{N}^c = \emptyset$.
    \item $A, B \in \mathbb{F}$, then $A^c, B^c$ are finite.  By De Morgan, $A^c \cup B^c = (A \cap B)^c$ is finite.  Hence $A \cap B \in \mathcal{F}$.
    \item If $A \in \mathcal{F}$ and $B \superseteq A$, then $B^c \subseteq A^c$ which is finite.  Hence, $B \in \mathcal{F}$.
\end{enumerate}

\subsubsection{Frechet Filter}
In the previous example, none of the properties used where special to the natural numbers.  Thus we can generalize to any infinite index set $I$.  Then
\[
\mathcal{F} = \{ A \subseteq I | A^c \textrm{ is finite} \}
\]
is a filter.  It is called the Frechet filter on I.

\subsubsection{Co-countable Filter}
This example can be extended even more by playing with the cardinalities involved.  For example, if $I$ is an uncountable set and
\[
\mathcal{F} = \{ A \subseteq I| A^c \textrm{ is countable}\}
\]
then $\mathcal{F}$ is the co-countable filter.

\subsubsection{A Filter from Measure Theory}
Let $(X, \Sigma, \mu)$ be a probability space, then
\[
\mathcal{F} = \{ A \subseteq X | \mu(A) = 1 \}
\]
is a filter.  It consists of the events which are certain to happen.

\subsubsection{Trivial Example}
If $X$ is a set, then
\[
\mathcal{F} = \{ X \}
\]
is a filter on $X$.  This is called the trivial filter on $X$.

\section{Limits}
Let $X$ be a topological space.  Let $(x_i)_{i \in I}$ be a family of elements of $X$ and let $a \in X$.  If $\mathcal{F}$ is a filter on $I$, we write
\[
x_i \xrightarrow{\mathcal{F}} y
\]
if $\forall$ neighborhoods $U$ of $a$
\[
\{ i | x_i \in U \} \in \mathcal{F}.
\]

\begin{remark}{}
If $I = \mathbb{N}$ and $\mathcal{F}$ is the Frechet filter, then for any sequence $(x_n)_{n \in \mathbb{N}}$,
\[
x_n \xrightarrow{\mathcal{F}} a
\]
if and only if $x_n \rightarrow a$ as $n \rightarrow \infty$ in the classical sense.
\end{remark}

\begin{definition}{Ultrafilter}
If $I$ is an index set then an ultrafilter $\mathcal{F}$ on $I$ is a filter such that $\forall A \subseteq I$, either $A \in \mathcal{F}$ or $A^c \in \mathcal{F}$.
\end{definition}

\begin{theorem}
If $I$ is any set and $\mathcal{F}$ is any filter on $I$, then there exists an ultrafilter $\mathcal{U}$ on $I$ such that $\mathcal{F} \subseteq \mathcal{U}$.
\end{theorem}
\end{document}


\subsection{Representation of images}

By the linear finite element discretization and bilinear finite element discretization,
we have \eqref{2d-fe0} and \eqref{2d-fe1} respectively.

As usual, the F-inner product is defined as follows:
$$
(u, v)_F := \sum_{i,j} u_{i,j}v_{i,j}.
$$

more general form for the discretization systems  is the so
called

As discussed above, the restriction mapping is consistent with

Here let us show a simple example about some details for computing deconvolution.

\subsubsection{Pooling or restriction}\label{sec:cnn-restriction}
Solving the residual equation
$$
K_A\ast e=r^h
$$
in matrix form is equivalent to solve the problem
\begin{equation}\label{FEres}
a(e_h, v_h)=(r_h,v_h)~~\forall~~v_h\in \mathcal V_h,
\end{equation}
where
\begin{equation}\label{expresion:residual}
e_h=\sum_{i=1}^{m_1}\sum_{j=1}^{n_1}e^h_{i,j}\phi^h_{i,j}(x,y), r_h=\sum_{i=1}^{m_1}\sum_{j=1}^{n_1}r^h_{i,j}\psi^h_{i,j}(x,y).
\end{equation}
We solve the equation \eqref{FEres} on the coarse grid space $\mathcal V_H$, namely
\begin{equation}\label{FEres:coarse}
a(e_{2h}, v_{2h})=(r_h,v_{2h})~~\forall~~v_{2h}\in \mathcal V_{2h},
\end{equation}
where $e_{2h}=\sum_{i=1}^{m_2}\sum_{j=1}^{n_2}e^{2h}_{i,j}\phi^{2h}_{i,j}(x,y)$, the matrix form for \eqref{FEres:coarse} is
\begin{equation}\label{coarse:matrix}
K_A\ast e^{2h}=r^{2h},~~r_{i,j}^{2h}=(r_h,\phi^{2h}_{i,j})
\end{equation}
\begin{equation}\label{restriction}
r_{i,j}^{2h}=(r_h,\phi^{2h}_{i,j})
\end{equation}
Now we consider the expression of nodal basis functions $(\phi_{i,j}^{2h})(x,y)\subset \mathcal V_{2h}$ by the nodal basis functions $(\phi_{i,j}^{h})(x,y)\subset \mathcal V_{h}$. Here, we only show the details of the case of bilinear finite element space.  The case of linear finite element space can be shown similarly.

 for general $\mathcal V_1=\mathcal  V_\ell,  \mathcal V_2=\mathcal  V_{\ell+1}$,

 \section{Multigrid for finite element methods}
Let $\mathcal  V_1=\mathcal  V_h$, then the finite element method: Find $u_h\in \mathcal  V_h$ such that
\begin{equation}\label{FEdis}
a(u_h, v_h)=(f, v_h)~~~\forall~~v_h\in \mathcal  V_h,
\end{equation}
where $a(u_h, v_h)=(\nabla u_h, \nabla v_h)$.
\begin{lemma}
FE $\rightarrow$ FD with $f_{i,j}=\int_{\Omega}f(x,y)\phi_{ij}(x,y)dxdy$.
\end{lemma}

For a more comprehensive notation, let us also define
$K\ast$ as an operator from $\mathbb{R}^{m\times n} \quad \text{and}$
to $\mathbb{R}^{m\times n}$ as $\mathcal C_K$.
Then we have the ``transpose'' of convolution without stride as:
\begin{equation}\label{eq:def_tran_conv}
(K \ast u, v)_F = (\mathcal C_K (u), v) =  (u,  \mathcal C_K^\top v).
\end{equation}

Finite element method: $A_h: \mathcal  V_h\rightarrow \mathcal  V_h, ~~(A_hu_h,v_h)_{L^2}=(\nabla u_h, \nabla v_h)$ (discrete Laplacian $A_h\approx -\Delta_h$. )
\begin{equation}\label{FE:eq}
A_hu_h=f_h,~~
\end{equation}
where~$f_h(x,y)=\sum_{i=1}^{m_1}\sum_{j=1}^{n_1}f_{i,j}\psi_{i,j}(x,y)$ in terms of dual basis $\psi_{i,j}(x,y)\subset \mathcal V_h$ satisfying \eqref{dual-basis}.

The gradient descent for \eqref{FE:eq} is equivalent to the damped Jacobi method for \eqref{FE:eq} and can be written as follows
$$
u^k=u^{k-1}+S_0(f-K_A\ast u^{k-1}),~~~1\le k\le m_1.
$$
Smoother is equivalent to filter (filtering out high frequncies). Given any $u^0$, $u-u^k$ is much smoother than $u-u^0$.

%Fine grid smoothing $\Longleftrightarrow$ feature extraction.

After smoothing, we do coarse grid correction: for example, for
$\mathcal T_h,~\mathcal T_H,~H=2h, \mathcal V_2=\mathcal V_H\subset \mathcal V_h=\mathcal V_1$, we do
\begin{itemize}
\item $K_A\ast e=f- K_A\ast u^{m_1}=r^h$;
\item  $u=u^{m_1}+e$;
\item  $K_A\ast u=f$.
\end{itemize}
We need to solve the residual equation
$$
K_A\ast e=r^h.
$$
Multigrid idea: solve this residual  equation on coarse grid space $\mathcal V_H$ with $H=2h$.

Let us first briefly describe a geometric multigrid method used to solve the
following boundary value problem
\begin{equation}
\label{laplace}
-\Delta u = f,  \mbox{ in } \Omega,\quad
\frac{\partial u}{\partial {\bm n}} =0  \mbox{ on } \partial\Omega,\quad
\Omega=(0,1)^2.
\end{equation}

As example, we consider a continuous linear finite element discretization of
\eqref{laplace} on a nested sequence of grids of sizes $n_\ell\times
n_\ell$ with $n_{\ell}=2^{J-\ell+1} + 1$, as shown in the right part of
Fig. \ref{fig:2dpartition} and the corresponding sequence of finite
element spaces.
%Here we need to notice that, $n_\ell = 2^{k_\ell} + 1$ for general PDEs grid
%with the above boundary condition. For general images, we can take them as
%discrete functions on grid with size $n_\ell = 2^{k_\ell}m$ with small $m = 1,3,\cdots$.
%Then generally speaking, the coarse grid size is $n_{\ell+1} = \frac{n_\ell}{2}=2^{k\ell - 1}m$.

Based on the grid $\mathcal T = \mathcal T_\ell$, the discretized system is
\begin{equation}
\label{laplace-h}
Au=f.
\end{equation}
Here,  $A:\mathbb R^{n\times n}\mapsto \mathbb R^{n\times n}$ is a tensor satisfying
\begin{equation}
\label{uniform-laplace}
(Au)_{i,j}=4u_{i,j}-u_{i+1,j}-u_{i-1,j}-u_{i,j+1}-u_{i,j-1},
\end{equation}
which holds for $1\le i,j \le n$ with zero padding.
Here we notice that, there exists a $3\times 3$ kernel as
\begin{equation}\label{eq:kernel-A}
K_A = \begin{pmatrix}
0 & -1 & 0 \\
-1 & 4 & -1 \\
0 & -1 & 0
\end{pmatrix},
\end{equation}
with
\begin{equation}\label{eq:convA}
Au = K_A \ast u.
\end{equation}
Where $\ast$ is the stander convolution operation with zero padding like \eqref{con1}.
We now briefly describe a simple multigrid method by a mixed use of the terminologies from
deep learning \cite{goodfellow2017deep} and multigrid methods.

However, because of the specially properties of
 An important results in multilevel finite element methods is that
if we take the restriction as \eqref{eq:restriction} with prolongation as
the transposition of restriction, we will have $A^2$ is still a convolution operation
with $K_{A^2} = K_{A^1} = K_A$ as in \eqref{eq:kernel-A}.

%	Note that $\sigma_\phi^{(k_0)}=\sigma\ast\phi^{(k_0)}=0$, this implies that $\sigma$ is a polynomial of degree at most $k_0-1$, which contradicts with the assumption that $\sigma$ is not a polynomial.
%	As a result, $\overline{\Sigma}_n$ contains all polynomials, hence is dense in $C(\mathbb{R})$.
%\end{proof}
%
%\begin{theorem}
%	\label{prop:riemann}
%		Let $\sigma$ be a non-polynomial Riemann integrable function and $\sigma\in L_{loc}^\infty(\mathbb{R})$. Then $\Sigma_1$ in dense in $C(\mathbb{R})$.
%	\end{theorem}
%\begin{proof}
%	The proof basically follows the proof of Proposition~\ref{prop:conti}. Let $\phi\in C_0^\infty(\mathbb{R})$, and consider $\sigma_\phi$. Again we assume $\mathrm{supp}(\phi)\subset[-\alpha,\alpha]$. Then we can take the Riemann sum $\sum_{i=1}^{m}\sigma(x-y_i)\phi(y_i)\Delta y_i$ where $y_i=-\alpha+\frac{2\alpha}{m}i$ and $\Delta y_i=\frac{2\alpha}{m}$ for $i=0:m$. Set $V_i=[y_{i-1}.y_i]$. The goal is to show that the Riemann sum uniformly converges to $\sigma_\phi$ on any compact set $K$.
%
%	For any compact set $K$, and any $x\in K$, still we need to do estimation similar to \eqref{uniconv}. Denote $\tilde{K}=K-[-\alpha,\alpha]$. Given $\delta>0$, since $\sigma$ is Riemann integrable, the set of discontinuous points is of measure 0, thus there exists a finite number $n(\delta)$ of intervals, the union of which denoted by $U$, such that the measure of $U$ is $\delta$ and $\sigma$ is uniformly continuous on $\tilde{K}\setminus U$.
%
%	Choose $\delta>0$ such that
%	\begin{equation}
%	\label{delta}
%	10\delta\|\sigma\|_{L^\infty(\tilde{K})}\|\phi\|_{L^\infty}\le\epsilon.
%	\end{equation}
%
%
%	Choose $m$ large enough such that $m\delta>\alpha n(\delta)$, and:
%	\begin{equation}
%	\label{m-large}
%	|\phi(x)-\phi(y)|\le\frac{\epsilon}{2\alpha\|\sigma\|_{L^\infty(\tilde{K})}},\qquad \forall |x-y|\le\frac{2\alpha}{m},
%	\end{equation}
%	and
%	\begin{equation}
%	\label{sigma}
%	|\sigma(x)-\sigma(y)|\le\frac{\epsilon}{\|\phi\|_{L^1}},\qquad x,y\in \tilde{K}\setminus U, |x-y|\le\frac{2\alpha}{m}.
%	\end{equation}
%
%	Then
%		\begin{equation}
%		\label{riemann}
%	\begin{aligned}
%	&|\int_{\mathbb{R}}\sigma(x-y)\phi(y)dy-\sum_{i=1}^{m}\sigma(x-y_i)\phi(y_i)\Delta y_i|,\\
%	\le&\sum_{i=1}^{m}\int_{V_i}|\sigma(x-y)-\sigma(x-y_i)||\phi(y)|+|\sigma(x-y_i)||\phi(y)-\phi(y_i)|dy.
%	\end{aligned}
%	\end{equation}
%	By \eqref{m-large}, we have:
%\begin{equation}
%\label{part1}
%\sum_{i=1}^{m}\int_{V_i}|\sigma(x-y_i)||\phi(y)-\phi(y_i)|dy\le\epsilon.
%\end{equation}
%When $(x-V_i)\bigcap U=\emptyset$, then by \eqref{sigma}
%	\begin{equation}
%	\label{part2}
%	\int_{V_i}|\sigma(x-y)-\sigma(x-y_i)||\phi(y)|dy\le\frac{\epsilon}{\|\phi\|_{L^1}}\int_{V_i}|\phi(y)|dy.
%	\end{equation}
%	Thus sum together we will get a term that is less than $\epsilon$.
%For those $V_i$'s intersect with $U$, the total length should be at most $\delta+\frac{4\alpha}{m}n(\delta)$ since there are $n(\delta)$ intervals in $U$. By the choice of $m$, we have $\delta+\frac{4\alpha}{m}n(\delta)\le5\delta$. Hence,
%	\begin{equation}
%\label{part3}
%\sum\int_{V_i}|\sigma(x-y)-\sigma(x-y_i)||\phi(y)|dy\le2\|\sigma\|_{L^\infty(\tilde{K})}\|\phi\|_{L^\infty}5\delta\le\epsilon.
%\end{equation}
%	Combine together we should have
%	$$
%	|\int_{\mathbb{R}}\sigma(x-y)\phi(y)dy-\sum_{i=1}^{m}\sigma(x-y_i)\phi(y_i)\Delta y_i|\le3\epsilon.
%	$$
%	which implies the convergence is uniform.
%
%	Then it left to show that there exists $\phi$ such that $\sigma_\phi$ is not a polynomial. If not, then there must be $k_0$ and $\phi$ such that $\sigma_\phi^{(k_0)}(\theta)=0$ for all $\theta\in\mathbb{R}$ and all $\phi\in C_0^\infty(\mathbb{R})$. Since for every compact set $K$, we should have:
%	$$
%	\|\sigma-\sigma_{\eta_\epsilon}\|_{L^p(K)}\to0,\quad1\le p<\infty, \quad \epsilon\to0.
%	$$
%	If $\sigma_{\eta_\epsilon}$'s are all polynomials of degree at most $k_0-1$, then $\sigma$ is also a polynomial of degree at most $k_0-1$ almost everywhere.
%
%	\end{proof}

Here, we have
\begin{equation*}
0=x_0<x_1<\cdots<x_{n+1}=1, \quad x_j=\frac{j}{n+1},\quad (j=0,\cdots, n+1).
\end{equation*}
and
\begin{equation*}
0=y_0<y_1<\cdots<y_{n+1}=1, \quad y_j=\frac{j}{n+1},\quad (j=0,\cdots,n+1).
\end{equation*}
\begin{figure}[H]
\begin{center}
\setlength{\unitlength}{0.5mm}
\begin{picture}(0,45)(10,0)
\linethickness{0.25mm}
\multiput(0,0)(10,0){5}{\line(0,1){40}}
\multiput(0,0)(0,10){5}{\line(1,0){40}}
\put(0,0){\line(1,1){40}}
\put(10,0){\line(1,1){30}}
\put(20,0){\line(1,1){20}}
\put(30,0){\line(1,1){10}}
%\put(40,0){\line(1,1){10}}
\put(0,10){\line(1,1){30}}
\put(0,20){\line(1,1){20}}
\put(0,30){\line(1,1){10}}
%\put(0,40){\line(1,1){10}}
\put(37,24){$\displaystyle \left. \begin{array}{l}~ \\ ~\end{array}
\right\} h={1\over n+1}$}
\put(44,4){$\displaystyle N = n^2$}
%\multiput(100,0)(10,0){6}{\line(0,1){50}}
%\multiput(100,0)(0,10){6}{\line(1,0){50}}
%\put(147,34){$\displaystyle \left. \begin{array}{l}~ \\ ~\end{array}
%\right\} h={1\over n+1}$}
%\put(154,14){$\displaystyle N = n^2$}
\end{picture}
%\setlength{\unitlength}{0.5mm}
\end{center}
\label{fig:2dpartition}
\caption{Two-dimensional uniform grid for finite element method}
\end{figure}

The weak form is: Find $u_h \in V_h$, such that
\begin{equation} \label{eqn:weak}
a(u_h, v_h) = (f, v_h), \ \forall \ v_h \in V_h
\end{equation}
where $a(u_h,v_h) = \int_{\Omega} \nabla u_h \nabla v_h $ and $(f, v_h) = \int_{\Omega} fv_h$, and $V_h$ is the corresponding linear finite element space.  Take $v_h = \phi^h_{i,j}$ where $\phi^h_{i,j}$ is the basis function at point $(x_i, y_j)$, from \eqref{eqn:weak}, we have

where ${A} = \text{tridiag}(-{I}, {B}, -{I})$ and ${B} = \text{tridiag}(-1,4,-1)$ and ${u} = ({u}_{i,j})$ and ${f} = ({f}_{i,j})$ with $i$ and $j$ both follow the lexicographic ordering.
\begin{enumerate}
\item \emph{Jacobi method:}  implement the Jacobi method as shown in the following algorithm
\

\begin{algorithm}
Jacobi method:  $[{u}^{k+1}] = \texttt{jacobi} ({u}^k, {f}, h)$
\begin{algorithmic}[1]
\STATE $n \gets \frac{1}{h} - 1$
\FOR{$j = 1:n$}
\FOR{$i = 1:n$}
\STATE $ {u}^{k+1}_{i,j} \gets {u}^{k+1}_{i,j } + ({f}_{i,j} + {u}^k_{i-1,j} + {u}^k_{i+1,j} + {u}^k_{i,j-1} + {u}^{k}_{i,j+1} -4 {u}^k_{i,j})/4$
\ENDFOR
\ENDFOR
\end{algorithmic}
\end{algorithm}

\

Choose right hand side $f$ and initial guess ${u}^0$ freely (constant right hand side and random initial guess are recommended), and use the stopping criterion $\| {f} - {A} {u}^k \| / \| {f} - {A} {u}^0 \|  \leq 10^{-6} $.  Make a table to report the number of iterations and CPU time for $h = 2^{-5}, 2^{-6}, \cdots, 2^{-8}$.

\item \emph{Gauss-Seidel method:}

It is easy to verify that the formulation for the linear element method is
\begin{equation}
  \label{2d-fe0}
4u_{ij}-(u_{i+1,j}+u_{i-1,j}+u_{i,j+1}+u_{i,j-1})=f_{i,j},~~u_{i,j}=0~~\hbox{if}~~i ~~\hbox{or}~~ j\in \{0, n+1\}.
\end{equation}
where ${f}_{i,j} = (f, \phi^h_{i,j})$.  This leads to the following linear system of equations.
\begin{equation*}
A \ast u = f,
\end{equation*}
where
\begin{equation}\label{eq:kernel-A}
A = \begin{pmatrix}
0 & -1 & 0 \\
-1 & 4 & -1 \\
0 & -1 & 0
\end{pmatrix}.
\end{equation}

%Implement the following gradient descent method:
%
%\
%
%%\begin{algorithm}
%\underline{\textbf{Gradient descent method:}}  $[{u}] = \texttt{GD} ({u}, {f}, n)$
%\begin{algorithmic}[1]
%%\STATE ${v} \gets {u}^{k}$
%%\STATE $n \gets \frac{1}{h} - 1$
%\FOR{$j = 1:n$}
%\FOR{$i = 1:n$}
%\STATE $ {u}_{i,j} \gets  {u}_{i,j} +\frac{1}{8}({f}_{i,j} -4 {u}_{i,j} +{u}_{i-1,j} +{u}_{i+1,j} +{u}_{i,j-1}+{u}_{i,j+1} )$
%\ENDFOR
%\ENDFOR
%\end{algorithmic}
%\end{algorithm}

as
 \begin{equation}
u \leftarrow u + \frac{1}{8}( f - K\ast u).
\end{equation}
This can be done with  the convolution

Especially if
$$
u^{0} = 0,
$$
we have
\begin{equation}
u^{1} \leftarrow S_0 \ast f,
\end{equation}
and if we apply the gradient descent iteration twice we have
\begin{equation}
u^{2} \leftarrow S_1 \ast f,
\end{equation}
with
\begin{equation}\label{eq:kernel-S}
S_0 = {1 \over 8},
\end{equation}
and
\begin{equation}\label{eq:kernel-S2}
S_1={1\over 64} \begin{pmatrix}
0 & 1 & 0 \\
1 & 12 & 1  \\
0 &1  & 0
\end{pmatrix}.
\end{equation}
\hrule

%Given an initial guess ${u}^0$, consider the gradient descent iteration as follows:
%
%
%
%\begin{algorithmic}[1]
%\STATE $k \gets 0$
%\WHILE{$\| {f} - {A} {u}^k \| / \| {f} - {A} {u}^0 \|  > \texttt{Tol}$}
%\STATE $[{u}^{k+1}] = \texttt{GD} ({u}^k, {f}, n)$
%\STATE $k \gets k+1$
%\ENDWHILE
%\end{algorithmic}

\

\eqref{conA}

 by convolution as
\begin{equation}
u \leftarrow K\ast u.
\end{equation}
This can be done with

%\hrule

\

%The restriction and prolongation are implemented as follows:
%
%\
%
%%\begin{algorithm} \label{alg:restrict}
%\underline{\textbf{Restriction:}} $[{r}^H] = \texttt{restrict}({r}^h, n_H)$
%\begin{algorithmic}[1]
%%\STATE $H = 2h$, $n_H = \frac{1}{H} - 1$
%\FOR{$j = 1:n_H$}
%\FOR{$i = 1:n_H$}
%\STATE ${r}^H_{i,j} \gets {r}^h_{2i,2j} + \frac{1}{2} \left( {r}^h_{2i+1,2j} + {r}^h_{2i-1,2j}  + {r}^h_{2i,2j+1}  + {r}^h_{2i,2j-1}  + {r}^h_{2i+1,2j+1} + {r}^h_{2i-1,2j-1}   \right)$
%\ENDFOR
%\ENDFOR
%\end{algorithmic}
%\end{algorithm}

\hrule

\begin{equation}
r^{H} = R \ast_2 r^h,
\end{equation}
with
\begin{equation}
\label{linear-restrict}
R=
\begin{pmatrix}
0 &\frac{1}{2}&\frac{1}{2}\\
\frac{1}{2}& 1&\frac{1}{2}\\
\frac{1}{2}&\frac{1}{2}&  0
\end{pmatrix}.
\end{equation}
\
This can be done with

%\hrule
%
%%\begin{algorithm}\label{alg:prolongate}
%\underline{\textbf{Prolongation:}} $[ {e}^h] = \texttt{prolongate}({e}^H, n_H)  $
%\begin{algorithmic}[1]
%%\STATE $n_H = \frac{1}{H} - 1$
%\FOR{$j = 0:n_H-1$}
%\FOR{$i = 0:n_H-1$}
%\STATE ${e}^h_{2i,2j} \gets {e}^H_{i,j}$
%\STATE ${e}^h_{2i+1,2j} \gets \frac{1}{2} ({e}^H_{i,j} + {e}^H_{i+1,j} )$
%\STATE ${e}^h_{2i+1,2j+1} \gets \frac{1}{2}( {e}^H_{i,j} + {e}^H_{i+1,j+1}) $
%\STATE ${e}^h_{2i,2j+1} \gets  \frac{1}{2} ({e}^H_{i,j} + {e}^H_{i,j+1})$
%\ENDFOR
%\ENDFOR
%\end{algorithmic}
%\end{algorithm}
%\hrule
\hrule

\begin{equation}
e^{h} =  R \ast_2^\top r^H,
\end{equation}
with
\begin{equation}
\label{linear-restrict}
R=
\begin{pmatrix}
0 &\frac{1}{2}&\frac{1}{2}\\
\frac{1}{2}& 1&\frac{1}{2}\\
\frac{1}{2}&\frac{1}{2}&  0
\end{pmatrix}.
\end{equation}
\
This can be done with

%Now, one step of the two-grid method with gradient descent smoother is defined as follows:
%
%\
%
%%\begin{algorithm}
%\underline{\textbf{Two-grid method:}} $[{u}] = \texttt{TwoGrid}( {u}, {f}, n, n_H)$
%\begin{algorithmic}[1]
% \STATE \emph{Smoothing:} $[{u}] = \texttt{GD} ({u}, {f}, n)$
%\STATE \emph{Compute residual:} ${r} \gets {f} - \texttt{Action}({u}, n) $
%\STATE \emph{Restriction:} $[{r}^{H}]= \texttt{restrict}({r}, n_H)$
%\STATE \emph{Coarse grid correction:} (Suppose to use $ {e}^{H} \gets {A}_{H}^{-1} {r}^{H}$, however, we cannot compute ${A}_H^{-1}$ since we do not form ${A}_H$ explicitly.  Therefore, we use sufficient steps of Gauss-Seidel method)
%\begin{enumerate}
%\item [\small{4.1:}] ${e}^{H} \gets {0}$
%\item [\small{4.2:}] \textbf{for} $m = 1: \texttt{coarse\_step}$ \textbf{do}
%\item [\small{4.3:}] \quad $[{e}^H] = \texttt{GD} ({e}^H, {r}^H, n_H)$
%\item [\small{4.4:}]  \textbf{end} \textbf{for}
%\end{enumerate}
%%\STATE ${e}^{H} \gets {0}$
%%\FOR{$m = 1: \texttt{coarse\_step}$}
%%\STATE $[{e}^H] = \texttt{GD} ({e}^H, {r}^H, H)$
%%\ENDFOR
%\STATE \emph{Prolongation:} ${u} \gets {u} + \texttt{prolongate}({e}^H, n_H) $
%\end{algorithmic}
%%\end{algorithm}
%
%\
%
%Given an initial guess ${u}^0$, please implement the two-grid iteration as follows:
%
%\begin{algorithmic}[1]
%\STATE $k \gets 0$
%\WHILE{$\| {f} - {A} {u}^k \| / \| {f} - {A} {u}^0 \|  > \texttt{Tol}$}
%\STATE $[{u}^{k+1}] = \texttt{TwoGrid} ({u}^k, {f}, n, n_H)$
%\STATE $k \gets k+1$
%\ENDWHILE
%\end{algorithmic}
%
%\
%
%Choose right hand side $f$ and initial guess ${u}^0$ freely (constant right hand side and random initial guess are recommended), and set the tolerance to be $\texttt{Tol} = 10^{-6}$.  Make a table to report the number of iterations, convergence factor ($\| {f} - {A} {u}^k \| / \| {f} - {A} {u}^{k-1} \|  $ ), and CPU time for $J = 3, 4, 5, 6$.

MG method is based on the following nested spaces
\begin{equation*}
\mathcal V_1 \subset \mathcal V_2 \subset \cdots \subset \mathcal V_J,
\end{equation*}
where $\mathcal V_\ell$, $\ell = 1, 2, \cdots, J$, are linear finite element spaces on uniform grids with mesh size $h_\ell = 2^{-\ell}$ and $n_\ell = 2^\ell-1$.
%The prolongation matrix ${I}_{l-1}^l \in \mathbb{R}^{N_l \times N_{l-1}}$ where $N_l = (1/h_l-1)^2$ are defined by the manner of \eqref{eqn:prolongation}.  Moreover, we also have the restriction matrix is the transpose of the prolongation matrix, i.e. ${I}_l^{l-1}: = ( {I}_{l-1}^l )^t$. And ${A}_{l-1} = {I}_l^{l-1} {A}_l  {I}_{l-1}^l $ with ${A}_J = {A}$.
Recursive implementation of the MG method with GD smoother is defined as follows:
%\begin{algorithm}

\

%\underline{\textbf{MG method:}} $[ {u}_l ] = \texttt{MultiGrid}({u}_l, {f}_l, l)$
%\begin{algorithmic}[1]
%\STATE $n_l \gets 2^l-1$, $n_{l-1} = 2^{l-1}-1$
%\IF{$l=1$}
%\STATE ${u}_1 \gets {A}_1^{-1} {f}_1$
%\ELSE
%\STATE \emph{Smoothing:} $[{u}_l] = \texttt{GD} ({u}_l, {f}_l, n_l)$
%\STATE \emph{Compute residual:} ${r}_l \gets {f}_l - \texttt{Action}({u}_l, n_l)$
%\STATE \emph{Restriction:} $[{r}_{l-1}] = \texttt{restrict}({r}_l, n_{l-1})$
%\STATE \emph{Coarse grid correction:} $[ {e}_{l-1} ] = \texttt{MultiGrid}({0}, {r}_{l-1}, l-1) $
%\STATE \emph{Prolongation:} ${u}_{l} \gets {u}_l + \texttt{prolongate}({e}_{l-1}, n_{l-1})$
%\ENDIF
%\end{algorithmic}
%%\end{algorithm}

%\underline{\textbf{MG method:}} $[ {u}^\ell ] = \texttt{MultiGrid}(0, {f}^\ell,\ell)$
%\begin{algorithmic}[1]
%	\STATE $n_\ell \gets 2^\ell-1$, $n_{\ell-1} = 2^{\ell-1}-1$
%	\IF{$\ell=1$}
%	\STATE ${u}^1 \gets {A}_1^{-1} {f}^1$
%	\ELSE
%	\STATE \emph{Smoothing:} $[{u}^\ell] = S \ast {f}^\ell$
%	\STATE \emph{Compute residual:} ${r}^\ell \gets {f}^\ell - A \ast {u}^\ell,$
%	\STATE \emph{Restriction:} $[{r}^{\ell-1}] = R \ast_2 {r}^\ell$
%	\STATE \emph{Coarse grid correction:} $[ {e}^{\ell-1} ] = \texttt{MultiGrid}({0}, {r}^{\ell-1}, \ell-1) $
%	\STATE \emph{Prolongation:} ${u}^{\ell} \gets {u}^\ell + R \ast_2^\top {e}^{\ell-1}$
%	\ENDIF
%\end{algorithmic}
%\end{algorithm}

\

Given an initial guess ${u}^0$, please implement the MG iteration as follows:

%\
%
%\begin{algorithmic}[1]
%\STATE $k \gets 0$
%\WHILE{$\| {f} - {A} {u}^k \| / \| {f} - {A} {u}^0 \|  > \texttt{Tol}$}
%\STATE $[{u}^{k+1}] = \texttt{MultiGrid} ({u}^k, {f}, J)$
%\STATE $k \gets k+1$
%\ENDWHILE
%\end{algorithmic}

\


\section{Spatial correlations of energetic disorder}
\label{sec:eanalyze}

\index{site energy!spatial correlation}
Long-range, e.g. electrostatic and polarization, interactions often result in spatially correlated disorder~\cite{dunlap_charge-dipole_1996}, which affects the onset of the mobility-field (Poole-Frenkel) dependence~\cite{derrida_velocity_1983,novikov_essential_1998,nagata_atomistic_2008}.

To quantify the degree of correlation, one can calculate the spatial correlation function of $E_i$ and $E_j$ at a distance $r_{ij}$
\begin{equation}
\label{equ:cf}
C(r_{ij}) = \frac{  \langle \left( E_i-\langle E\rangle \right)
                   \left( E_j-\langle E\rangle \right)\rangle}
                   {\langle\left( E_i -\langle E\rangle \right)^2\rangle},
\end{equation}
where $\langle E\rangle$ is the average site energy. $C(r_{ij})$ is zero if $E_i$ and $E_j$ are uncorrelated and $1$ if they are fully correlated. For a system of randomly oriented point dipoles, the correlation function decays as $1/r$ at large distances~\cite{novikov_cluster_1995}.

For systems with spatial correlations, variations in site energy differences, $\Delta E_{ij}$, of pairs of molecules from the neighbor list are smaller than variations in site energies, $E_i$, of all individual molecules. Since only neighbor list pairs affect transport, the distribution of $\Delta E_{ij}$ rather than that of individual site energies, $E_i$, should be used to characterize energetic disorder.

Note that the \calc{eanalyze} calculator takes into account {\em all} contributions to the site energies
\votcacommand{Analyze distribution and correlations of site energeies}{\cmdeana}


\documentclass{article}

\usepackage{graphicx}      % include this line if your document contains figures
\usepackage{cite}        % required for bibliography
\usepackage{amsmath,mathtools,amssymb}
\usepackage{amsfonts}
\usepackage{xcolor}
\usepackage{tikz}
\usepackage{pgfplots}
\usetikzlibrary{external}
\tikzexternalize[prefix=tikz/]
\usepackage{epstopdf}
\usepackage[font=footnotesize, labelfont={sf,bf}, margin=1cm]{caption}
\usepackage{graphicx}
\usepackage{algorithm}
\usepackage{algpseudocode}
\usepackage{booktabs}
\usepackage{caption}
%
\setlength\parindent{0pt}
\setlength{\parskip}{1em}
%
%\makeatletter
%\def\BState{\State\hskip-\ALG@thistlm}
%\makeatother
%
%\newcommand{\dd}{{\mathrm{d}}}
%
%\usetikzlibrary{decorations.pathreplacing,calc}

%\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture] \node (#1) {};}
%
\newcommand{\R}{\mathbb{R}}
%
%\newlength\figurewidth
%\newlength\figureheight
%
%\newtheorem{theorem}{Theorem}
%\newtheorem{corollary}{Corollary}[theorem]
%%\newtheorem{lemma}{Lemma}
%\newtheorem{lemma}[theorem]{Lemma}
%\newtheorem{assumption}{Assumption}
%\newtheorem {Remark}[theorem]{Remark}
%
%\makeatletter
%\renewcommand*\env@matrix[1][\arraystretch]{%
%	\edef\arraystretch{#1}%
%	\hskip -\arraycolsep
%	\let\@ifnextchar\new@ifnextchar
%	\array{*\c@MaxMatrixCols c}}
%\makeatother

%\newtheoremstyle{exampstyle}
%  {\topsep} % Space above
%  {\topsep} % Space below
%  {} % Body font
%  {} % Indent amount
%  {\bfseries} % Theorem head font
%  {.} % Punctuation after theorem head
%  {.5em} % Space after theorem head
%  {} % Theorem head spec (can be left empty, meaning `normal')

%\definecolor{bluet}{RGB}{100,121,178}
%\definecolor{redt}{RGB}{255,86,73}
%\definecolor{dgreent}{RGB}{75,212,69}

\expandafter\def\expandafter\normalsize\expandafter{%
	\normalsize
	\setlength\abovedisplayskip{10pt}
	\setlength\belowdisplayskip{10pt}
	\setlength\abovedisplayshortskip{10pt}
	\setlength\belowdisplayshortskip{10pt}
}
%
%
%\def\nonfrenchspacing{\sfcode`\.3000\sfcode`\?3000\sfcode`\!3000%
%	\sfcode`\:1000\sfcode`\;1500\sfcode`\,1250 }
%%
%\nonfrenchspacing
%
%\newcommand{\barr}{\begin{array}}
%	\newcommand{\earr}{\end{array}}
%\newcommand{\bvec}{ \left[ \!\! \barr{cccccccccccc} }
%\newcommand{\evec}{ \earr \!\! \right] }
%
%
%\hyphenation{op-tical net-works semi-conduc-tor}

\title{Notes on Initialization Strategies for \\ Primal-Dual Interior Point Methods}
\author{Andrea Zanelli}
\let\endtitlepage\relax

\begin{document}

\begin{titlepage}
	\maketitle
\end{titlepage}

%\section{Initialization strategy for general polytopic constraints.}
Consider the following convex quadratic problem (QP) with general polytopic constraints:
\begin{equation}\label{eq:u_qp}
\begin{aligned}
&\underset{\begin{subarray}{c}
	x \\
	\end{subarray}}{\min}	&&\frac{1}{2}x^THx\\
&\quad \text{s.t.} 		   	&&Ax  = b\\
& 						&&Cx \leq d,
\end{aligned}
\end{equation}
where $A \in \R^{m \times n}$, $C \in \R^{p \times n}$, $H \in \R ^{n\times n}$ and $H \succ 0$,  and $x \in \R^n$, $b \in \R^m$, $d \in \R^p$. We are interested in solving the above problem with a primal-dual infeasible interior-point method (IPM). To this end, we can write the following set of equations:
\begin{equation}\label{eq:u_kkt}
\begin{aligned}
&Hx + A^T\lambda + C^T\nu &&= 0 \\
&Ax - b 								&&= 0 \\
&Cx - d + s								&&= 0 \\
&S\nu									&&=0,
\end{aligned}
\end{equation}
where the slack variable $s \in \R^p$ has been introduced. Equations \eqref{eq:u_kkt}, together with the positivity constraints $s, \,\nu \!> \!0$ constitute the first-order optimality, or Karush-Kuhn-Tucker conditions (KKTs) associated with \eqref{eq:u_qp}.
\par

When using infeasible IPMs, a feasible point with respect to inequalities is required to be available to initialize the algorithm in order to be able to prove convergence of the iterates to the solution of the problem (if it exists). However, finding a point that lies inside the set defined by the polytopic constraints $Cx \leq d$ might be a computationally expensive task. For this reason, the following modified problem formulation can be used:
\begin{equation}\label{eq:qp}
\begin{aligned}
&\underset{\begin{subarray}{c}
	x,\,y \\
	\end{subarray}}{\min}	&&\frac{1}{2}x^THx\\
&\quad \text{s.t.} 		   	&&Ax  = b\\
& 						&&Cx = y \\
& 						&&y \leq d,
\end{aligned}
\end{equation}
where the additional constraint $Cx = y$ and the additional variable $y$ have been introduced in order to ``lift'' the inequality constraints and deal with the simpler constraint $y \leq d$. The Lagrangian of the modified problem is
\begin{equation}
\mathcal{L} = \frac{1}{2}x^THx + \lambda^T(Ax - b) + \mu^T(Cx - y) + \nu^T(y - d)
\end{equation}
and the KKTs associated with \eqref{eq:qp} read
\begin{equation}\label{eq:kkt}
\begin{aligned}
&Hx + A^T\lambda + C^T\mu &&= 0 \\
&-\mu + \nu &&= 0 \\
&Ax - b 								&&= 0 \\
&Cx - y								&&= 0 \\
&y - d + s									&&=0 \\
&S\nu &&=0.
\end{aligned}
\end{equation}
When solving QP problems arising from MPC formulations, due to the presence of additional equality constraints $Cx = y$, the efficient Riccati-based factorization propsed in \cite{Frison2013} cannot be applied straightforwardly. For this reason, we propose below an efficient elimination technique is proposed that brings the problem into the same form as in \eqref{eq:u_kkt}. In this way the Ricatti-based factorization can be applied to the reduced problem.
\par
The Newton system associated with \eqref{eq:kkt} reads:
\begin{equation}
\begin{bmatrix}
H & 0	& A^T 	& C^T	& 0 & 0 	\\
0 & 0	& 0 	& -I	& I & 0		\\
A & 0	& 0 	&  0	& 0 & 0		\\
C & -I	& 0 	&  0	& 0 & 0		\\
0 & I	& 0 	&  0	& 0 & I	\\
0 & 0	& 0 	& 0		& S & V		\\
\end{bmatrix}
\begin{bmatrix}
\Delta x \\ \Delta y \\ \Delta \lambda \\ \Delta \mu \\\Delta \nu \\ \Delta s
\end{bmatrix}
=
-\begin{bmatrix}
r_{S} \\ r_{S'} \\ r_E \\ r_{E'} \\ r_I \\ r_C
\end{bmatrix}.
\end{equation}
The system can be efficiently reduced by eliminating $\Delta y$ using the fact that $\Delta y = -\Delta s - r_I$:
\begin{equation}
\begin{bmatrix}
H 	& A^T 	& C^T	& 0 & 0 	\\
0 	& 0 	& -I	& I & 0		\\
A 	& 0 	&  0	& 0 & 0		\\
C 	& 0 	&  0	& 0 & I	\\
0 	& 0 	& 0		& S & V		\\
\end{bmatrix}
\begin{bmatrix}
\Delta x \\ \Delta \lambda \\ \Delta \mu \\\Delta \nu \\ \Delta s
\end{bmatrix}
=
-\begin{bmatrix}
r_{S} \\ r_{S'} \\ r_E \\ r_{E''} \\ r_C
\end{bmatrix},
\end{equation}
where $r_{E''} = r_{E'} + r_I$. Finally $\Delta \mu$ can be eliminated  using $\Delta \mu = \Delta \nu + r_{S'}$:
\begin{equation}
\begin{bmatrix}
H 	& A^T 	& C^T 	&	 0 	\\
A 	& 0 	& 0 	& 0		\\
C 	& 0 	& 0 	& I	\\
0 	& 0 	& S 	& V		\\
\end{bmatrix}
\begin{bmatrix}
\Delta x \\ \Delta \lambda \\\Delta \nu \\ \Delta s
\end{bmatrix}
=
-\begin{bmatrix}
r_{S''}  \\ r_E \\ r_{E''} \\ r_C
\end{bmatrix},
\end{equation}
where $r_{S''} = r_S + C^Tr_{S'}$
\bibliographystyle{plain}
\bibliography{syscop}
\end{document}


\chapter{Proof Tools: Propositional Logic}
\label{chap:proof-tools}

\newcommand{\naive}{na\"\i{}ve}

Users of \HOL{} can create their own theorem proving tools by
combining predefined rules and tactics. The \ML{} type-discipline
ensures that only logically sound methods can be used to create values
of type \ml{thm}.  In this chapter, a real example is described.

Two implementations of the tool are given to illustrate various styles
of proof programming. The first implementation is the obvious one, but
is inefficient because of the `brute force' method used. The second
implementation attempts to be a great deal more intelligent.
Extensions to the tools to allow more general applicability are also
discussed.

The problem to be solved is that of deciding the truth of a closed
formula of propositional logic.  Such a formula has the general form
\[
\begin{array}{ccl}
\varphi & ::= & v \;|\;\neg\varphi\;|\;\varphi
\land \varphi \;|\; \varphi \lor \varphi \;|\; \varphi \Rightarrow
\varphi\;|\;\varphi = \varphi
\\[1ex]
\mathit{formula} &::= & \forall \vec{v}. \;\varphi
\end{array}
\]
where the variables $v$ are all of boolean type, and where the
universal quantification at the outermost level captures all of the
free variables.

\section{Method 1: Truth Tables}

\setcounter{sessioncount}{0}

The first method to be implemented is the brute force method of trying
all possible boolean combinations.  This approach's only real virtue
is that it is exceptionally easy to implement.  First we will prove
the motivating theorem:
\begin{hol}
\begin{verbatim}
   val FORALL_BOOL = prove(
     ``(!v. P v) = P T /\ P F``,
     SRW_TAC [][EQ_IMP_THM] THEN Cases_on `v` THEN SRW_TAC [][]);
\end{verbatim}
\end{hol}
The proof proceeds by splitting the goal into two halves, showing
\[
(\forall v. \;P(v))\Rightarrow P(\top) \land P(\bot)
\]
(which goal is automatically shown by the simplifier), and
\[
P(\top) \land P(\bot) \Rightarrow P(v)
\]
for an arbitrary boolean variable $v$.  After case-splitting on $v$,
the assumptions are then enough to show the goal.  (This theorem is
actually already proved in the theory \theoryimp{bool}.)

The next, and final, step is to rewrite with this theorem:
\begin{hol}
\begin{verbatim}
   val tautDP = SIMP_CONV bool_ss [FORALL_BOOL]
\end{verbatim}
\end{hol}

This enables the following

\begin{session}
\begin{verbatim}
- tautDP ``!p q. p /\ q /\ ~p``;
> val it = |- (!p q. p /\ q /\ ~p) = F : thm

- tautDP ``!p. p \/ ~p``
> val it = |- (!p. p \/ ~p) = T : thm
\end{verbatim}
\end{session}
and even the marginally more intimidating
\begin{session}
\begin{verbatim}
- time tautDP
     ``!p q c a. ~(((~a \/ p /\ ~q \/ ~p /\ q) /\
                    (~(p /\ ~q \/ ~p /\ q) \/ a)) /\
                   (~c \/ p /\ q) /\ (~(p /\ q) \/ c)) \/
                 ~(p /\ q) \/ c /\ ~a``;
runtime: 0.147s,    gctime: 0.012s,     systime: 0.000s.
> val it =
    |- (!p q c a.
          ~(((~a \/ p /\ ~q \/ ~p /\ q) /\ (~(p /\ ~q \/ ~p /\ q) \/ a)) /\
            (~c \/ p /\ q) /\ (~(p /\ q) \/ c)) \/ ~(p /\ q) \/ c /\ ~a) =
       T : thm
\end{verbatim}
\end{session}

This is a dreadful algorithm for solving this problem.  The system's
built-in function, \ml{tautLib.TAUT\_CONV}, solves the problem above
much faster.  The only real
merit in this solution is that it took one line to write.  This is a
general illustration of the truth that \HOL{}'s high-level tools,
particularly the simplifier, can provide fast prototypes for a variety
of proof tasks.

\section{Method 2: the DPLL Algorithm}

The Davis-Putnam-Loveland-Logemann method~\cite{DPLL-paper} for
deciding the satisfiability of propositional formulas in CNF
(Conjunctive Normal Form) is a powerful technique, still used in
state-of-the-art solvers today.  If we strip the universal quantifiers
from our input formulas, our task can be seen as determining the
validity of a propositional formula.  Testing the negation of such a
formula for satisfiability is a test for validity: if the formula's
negation is satisfiable, then it is not valid (the satisfying
assignment will make the original false); if the formula's negation is
unsatisfiable, then the formula is valid (no assignment can make it
false).

\smallskip
\noindent
(The source code for this example is available in the file \texttt{examples/dpll.sml}.)

\subsection*{Preliminaries}

To begin, assume that we have code already to convert arbitrary
formulas into CNF{}, and to then decide the satisfiability of these
formulas.  Assume further that if the input to the latter procedure is
unsatisfiable, then it will return with a theorem of the form
\[ \vdash \varphi = \holtxt{F}
\]
or if it is satisfiable, then it will return a satisfying assignment,
a map from variables to booleans.   This map will be a function from
\HOL{} variables to one of the \HOL{} terms \holtxt{T} or \holtxt{F}.
Thus, we will assume
\begin{hol}
\begin{verbatim}
   datatype result = Unsat of thm | Sat of term -> term
   val toCNF : term -> thm
   val DPLL : term -> result
\end{verbatim}
\end{hol}
(The theorem returned by \ml{toCNF} will equate the input term to
another in CNF{}.)

\smallskip
\noindent
Before looking into implementing these functions, we will need to
consider
\begin{itemize}
\item how to transform our inputs to suit the function; and
\item how to use the outputs from the functions to produce our desired
  results
\end{itemize}

We are assuming our input is a universally quantified formula.  Both
the CNF and DPLL procedures expect formulas without quantifiers.  We
also want to pass these procedures the negation of the original
formula.  Both of the required term manipulations required can be done
by functions found in the structure \ml{boolSyntax}.  (In general,
important theories (such as \theoryimp{bool}) are accompanied by
\ml{Syntax} modules containing functions for manipulating the
term-forms associated with that theory.)

In this case we need the functions
\begin{hol}
\begin{verbatim}
   strip_forall : term -> term list * term
   mk_neg       : term -> term
\end{verbatim}
\end{hol}
The function \ml{strip\_forall} strips a term of all its outermost
universal quantifications, returning the list of variables stripped
and the body of the quantification.  The function \ml{mk\_neg} takes a
term of type \holtxt{bool} and returns the term corresponding to its
negation.

Using these functions, it is easy to see how we will be able to take
$\forall\vec{v}.\;\varphi$ as input, and pass the term $\neg\varphi$
to the function \ml{toCNF}.  A more significant question is how to
use the results of these calls.   The call to \ml{toCNF} will return a
theorem
\[
\vdash \neg\varphi = \varphi'
\]
The formula $\varphi'$ is what will then be passed to \ml{DPLL}.  (We
can extract it by using the \ml{concl} and \ml{rhs} functions.) If
\ml{DPLL} returns the theorem $\vdash \varphi' = \holtxt{F}$, an
application of \ml{TRANS} to this and the theorem displayed above will
derive the formula $\vdash \neg\varphi = F$.  In order to derive the
final result, we will need to turn this into $\vdash\varphi$.  This is
best done by proving a bespoke theorem embodying the equality (there
isn't one such already in the system):
\begin{hol}
\begin{verbatim}
   val NEG_EQ_F = prove(``(~p = F) = p``, REWRITE_TAC []);
\end{verbatim}
\end{hol}
To turn $\vdash \varphi$ into $\vdash (\forall
\vec{v}.\;\varphi) = \holtxt{T}$, we will perform the following proof:
\[
\infer[\texttt{\scriptsize EQT\_INTRO}]{
  \vdash (\forall \vec{v}.\;\varphi) = \holtxt{T}}{
  \infer[\texttt{\scriptsize GENL}(\vec{v})]{\vdash \forall \vec{v}.\;\varphi}{
    \vdash \varphi
  }
}
\]
The other possibility is that \ml{DPLL} will return a satisfying
assignment demonstrating that $\varphi'$ is satisfiable.  If this is
the case, we want to show that $\forall\vec{v}.\;\varphi$ is false.
We can do this by assuming this formula, and then specialising the
universally quantified variables in line with the provided map.  In
this way, it will be possible to produce the theorem
\[
\forall \vec{v}.\;\varphi \vdash \varphi[\vec{v} := \mbox{\emph{satisfying
  assignment}}]
\]
Because there are no free variables in $\forall\vec{v}.\;\varphi$, the
substitution will produce a completely ground boolean formula.  This
will straightforwardly rewrite to \holtxt{F} (if the assignment
makes $\neg\varphi$ true, it must make $\varphi$ false).  Turning
$\phi\vdash \holtxt{F}$ into $\vdash \phi = \holtxt{F}$ is a matter of
calling \ml{DISCH} and then rewriting with the built-in theorem
\ml{IMP\_F\_EQ\_F}:
\[
\vdash \forall t.\;t \Rightarrow \holtxt{F} = (t = \holtxt{F})
\]
Putting all of the above together, we can write our wrapper function,
which we will call \ml{DPLL\_UNIV}, with the \ml{UNIV} suffix
reminding us that the input must be universally quantified.
\begin{hol}
\begin{verbatim}
   fun DPLL_UNIV t = let
     val (vs, phi) = strip_forall t
     val cnf_eqn = toCNF (mk_neg phi)
     val phi' = rhs (concl cnf_eqn)
   in
     case DPLL phi' of
       Unsat phi'_eq_F => let
         val negphi_eq_F = TRANS cnf_eqn phi'_eq_F
         val phi_thm = CONV_RULE (REWR_CONV NEG_EQ_F) negphi_eq_F
       in
         EQT_INTRO (GENL vs phi_thm)
       end
     | Sat f => let
         val t_assumed = ASSUME t
         fun spec th =
             spec (SPEC (f (#1 (dest_forall (concl th)))) th)
             handle HOL_ERR _ => REWRITE_RULE [] th
       in
         CONV_RULE (REWR_CONV IMP_F_EQ_F) (DISCH t (spec t_assumed))
       end
   end
\end{verbatim}
\end{hol}

The auxiliary function \ml{spec} that is used in the second case
relies on the fact that \ml{dest\_forall} will raise a \ml{HOL\_ERR}
exception if the term it is applied to is not universally quantified.
When \ml{spec}'s argument is not universally quantified, this means
that the recursion has bottomed out, and all of the original formula's
universal variables have been specialised.  Then the resulting formula
can be rewritten to false (\ml{REWRITE\_RULE}'s built-in rewrites will
handle all of the necessary cases).

The \ml{DPLL\_UNIV} function also uses \ml{REWR\_CONV} in two places.
The \ml{REWR\_CONV} function applies a single (first-order) rewrite at
the top of a term.  These uses of \ml{REWR\_CONV} are done within
calls to the \ml{CONV\_RULE} function.  This lifts a conversion $c$ (a
function taking a term $t$ and producing a theorem $\vdash t = t'$),
so that $\ml{CONV\_RULE}\;c$ takes the theorem $\vdash t$ to $\vdash t'$.

\subsection{Conversion to Conjunctive Normal Form}
\label{sec:conv-conj-norm}

A formula in Conjunctive Normal Form is a conjunction of disjunctions
of literals (either variables, or negated variables).  It is possible
to convert formulas of the form we are expecting into CNF by simply
rewriting with the following theorems
\begin{eqnarray*}
\neg (\phi \land \psi) &=& \neg\phi \lor \neg\psi\\
\neg (\phi \lor \psi) &=& \neg\phi \land \neg\psi\\
\phi \lor (\psi \land \xi) &=& (\phi \lor \psi) \land (\phi \lor \xi)\\
(\psi \land \xi)\lor\phi \ &=& (\phi \lor \psi) \land (\phi \lor
\xi)\\[1ex]
\phi \Rightarrow\psi &=& \neg\phi \lor \psi\\
(\phi = \psi) &=& (\phi \Rightarrow \psi) \land (\psi \Rightarrow
\phi)
\end{eqnarray*}
Unfortunately, using these theorems as rewrites can result in an
exponential increase in the size of a formula.  (Consider using them
to convert an input in Disjunctive Normal Form, a disjunction
of conjunctions of literals, into CNF{}.)

A better approach is to convert to what is known as ``definitional
CNF''. \HOL{} includes functions to do this in the structure
\ml{defCNF}.  Unfortunately, this approach adds extra, existential,
quantifiers to the formula.  For example
\begin{session}
\begin{verbatim}
- defCNF.DEF_CNF_CONV ``p \/ (q /\ r)``;
> val it =
    |- p \/ q /\ r =
       ?x. (x \/ ~q \/ ~r) /\ (r \/ ~x) /\ (q \/ ~x) /\ (p \/ x) : thm
\end{verbatim}
\end{session}
Under the existentially-bound \holtxt{x}, the code has produced a
formula in CNF{}.  With an example this small, the formula is actually
bigger than that produced by the \naive{} translation, but with more
realistic examples, the difference quickly becomes significant.  The
last example used with \ml{tautDP} is 20 times bigger when translated
\naive{}ly than when using \ml{defCNF}, and the translation takes 150
times longer to perform.

But what of these extra existentially quantified variables?  In fact,
we can ignore the quantification when calling the core DPLL procedure.
If we pass the unquantified body to DPLL, we will either get back an
unsatisfiable verdict of the form $\vdash \varphi' = \holtxt{F}$, or a
satisfying assignment for all of the free variables.  If the latter
occurs, the same satisfying assignment will also satisfy the
original.  If the former, we will perform the following proof
\[
\infer{\vdash (\exists \vec{x}.\;\varphi') = \holtxt{F}}{
  \infer{\vdash (\exists \vec{x}.\;\varphi') \Rightarrow \holtxt{F}}{
    \infer{\vdash\forall \vec{x}.\;\varphi' \Rightarrow \holtxt{F}}{
      \infer{\vdash\varphi' \Rightarrow \holtxt{F}}{
        \vdash \varphi' = \holtxt{F}
      }
    }
  }
}
\]
producing a theorem of the form expected by our \ml{wrapper}
function.

In fact, there is an alternative function in the \ml{defCNF} API that
we will use in preference to \ml{DEF\_CNF\_CONV}.   The problem with
\ml{DEF\_CNF\_CONV} is that it can produce a big quantification,
involving lots of variables.  We will rather use
\ml{DEF\_CNF\_VECTOR\_CONV}.  Instead of output of the form
\[
\vdash \varphi = (\exists \vec{x}.\; \varphi')
\]
this second function produces
\[
\vdash \varphi = (\exists (v : \textsf{num} \rightarrow
\textsf{bool}).\; \varphi')
\]
where the individual variables $x_i$ of the first formula are replaced
by calls to the $v$ function $v(i)$, and there is just one quantified
variable, $v$.  This variation will not affect the operation of the
proof sketched above.  And as long as we don't require literals to be
variables or their negations, but also allow them to be terms of
the form $v(i)$ and $\neg v(i)$ as well, then the action of the DPLL
procedure on the formula $\varphi'$ won't be affected either.

Unfortunately for uniformity, in simple cases, the definitional CNF
conversion functions may not result in any existential
quantifications at all.  This makes our implementation of \ml{DPLL}
somewhat more complicated.  We calculate a \ml{body} variable that
will be passed onto the \ml{CoreDPLL} function, as well as a
\ml{transform} function that will transform an unsatisfiability result
into something of the desired form.  If the result of conversion to
CNF produces an existential quantification, we use the proof sketched
above.  Otherwise, the transformation can be the identity function,
\ml{I}:
\begin{hol}
\begin{verbatim}
   fun DPLL t = let
     val (transform, body) = let
       val (vector, body) = dest_exists t
       fun transform body_eq_F = let
         val body_imp_F = CONV_RULE (REWR_CONV (GSYM IMP_F_EQ_F)) body_eq_F
         val fa_body_imp_F = GEN vector body_imp_F
         val ex_body_imp_F = CONV_RULE FORALL_IMP_CONV fa_body_imp_F
       in
         CONV_RULE (REWR_CONV IMP_F_EQ_F) ex_body_imp_F
       end
     in
       (transform, body)
     end handle HOL_ERR _ => (I, t)
   in
     case CoreDPLL body of
       Unsat body_eq_F => Unsat (transform body_eq_F)
     | x => x
   end
\end{verbatim}
\end{hol}
where we have still to implement the core DPLL procedure (called
\ml{CoreDPLL} above).  The above code uses \ml{REWR\_CONV} with the
\ml{IMP\_F\_EQ\_F} theorem to affect two of the proof's
transformations.  The \ml{GSYM} function is used to flip the
orientation a theorem's top-level equalities.  Finally, the
\ml{FORALL\_IMP\_CONV} conversion takes a term of the form
\[
\forall x.\;P(x) \Rightarrow Q
\]
and returns the theorem
\[
\vdash (\forall x.\;P(x) \Rightarrow Q) = ((\exists
x.\;P(x))\Rightarrow Q)
\]

\subsection{The Core DPLL Procedure}
\label{sec:dpll-procedure}

The DPLL procedure can be seen as a slight variation on the basic
``truth table'' technique we have already seen.  As with that
procedure, the core operation is a case-split on a boolean variable.
There are two significant differences though: DPLL can be seen as a
search for a satisfying assignment, so that if picking a variable to
have a particular value results in a satisfying assignment, we do not
need to also check what happens if the same variable is given the
opposite truth-value.  Secondly, DPLL takes some care to pick good
variables to split on.  In particular, \emph{unit propagation} is used
to eliminate variables that will not cause branching in the
search-space.

Our implementation of the core DPLL procedure is a function that takes
a term and returns a value of type \ml{result}: either a theorem
equating the original term to false, or a satisfying assignment (in
the form of a function from terms to terms).  As the DPLL search for a
satisfying assignment proceeds, an assignment is incrementally
constructed.  This suggests that the recursive core of our function
will need to take a term (the current formula) and a context (the
current assignment) as parameters.  The assignment can be naturally
represented as a set of equations, where each equation is either $v =
\holtxt{T}$ or $v = \holtxt{F}$.

This suggests that a natural representation for our program state is a
theorem: the hypotheses will represent the assignment, and the
conclusion can be the current formula.  Of course, \HOL{} theorems
can't just be wished into existence.  In this case, we can make
everything sound by also assuming the initial formula.  Thus, when we
begin our initial state will be $\phi\vdash\phi$.  After splitting on
variable $v$, we will generate two new states
$\phi,(v\!=\!\holtxt{T})\vdash \phi_1$, and
$\phi,(v\!=\!\holtxt{F})\vdash \phi_2$, where the $\phi_i$ are the
result of simplifying $\phi$ under the additional assumption
constraining $v$.

The easiest way to add an assumption to a theorem is to use the
rule \ml{ADD\_ASSUM}.  But in this situation, we also want to
simplify the conclusion of the theorem with the same assumption.  This
means that it will be enough to rewrite with the theorem
$\psi\vdash\psi$, where $\psi$ is the new assumption.  The action of
rewriting with such a theorem will cause the new assumption to appear
among the assumptions of the result.

The \ml{casesplit} function is thus:
\begin{hol}
\begin{verbatim}
   fun casesplit v th = let
     val eqT = ASSUME (mk_eq(v, boolSyntax.T))
     val eqF = ASSUME (mk_eq(v, boolSyntax.F))
   in
     (REWRITE_RULE [eqT] th, REWRITE_RULE [eqF] th)
   end
\end{verbatim}
\end{hol}

A case-split can result in a formula that has been rewritten all the
way to true or false.  These are the recursion's base cases. If the
formula has been rewritten to true, then we have found a satisfying
assignment, one that is now stored for us in the hypotheses of the
theorem itself.  The following function, \ml{mk\_satmap}, extracts
those hypotheses into a finite-map, and then returns the lookup
function for that finite-map:
\begin{hol}
\begin{verbatim}
   fun mk_satmap th = let
     val hyps = hypset th
     fun foldthis (t,acc) = let
       val (l,r) = dest_eq t
     in
       Binarymap.insert(acc,l,r)
     end handle HOL_ERR _ => acc
     val fmap = HOLset.foldl foldthis (Binarymap.mkDict Term.compare) hyps
   in
     Sat (fn v => Binarymap.find(fmap,v)
                  handle Binarymap.NotFound => boolSyntax.T)
   end
\end{verbatim}
\end{hol}
The \ml{foldthis} function above adds the equations that are stored as
hypotheses into the finite-map.  The exception handler in
\ml{foldthis} is necessary because one of the hypotheses will be the
original formula.  The exception handler in the function that looks up
variable bindings is necessary because a formula may be reduced to
true without every variable being assigned a value at all.  In this
case, it is irrelevant what value we give to the variable, so we
arbitrarily map such variables to \holtxt{T}.

If the formula has been rewritten to false, then we can just return
this theorem directly.  Such a theorem is not quite in the right form
for the external caller, which is expecting an equation, so if the
final result is of the form $\phi\vdash \holtxt{F}$, we will have to
transform this to $\vdash \phi = \holtxt{F}$.

The next question to address is what to do with the results of
recursive calls.  If a case-split returns a satisfying assignment this
can be returned unchanged.  But if a recursive call returns a theorem
equating the input to false, more needs to be done.  If this is the
first call, then the other branch needs to be checked.  If this also
returns that the theorem is unsatisfiable, we will have two theorems:
\[
\phi_0,\Delta,(v\!=\!\holtxt{T})\vdash \holtxt{F} \qquad
\phi_0,\Delta,(v\!=\!\holtxt{F})\vdash \holtxt{F}
\] where $\phi_0$ is the original formula, $\Delta$ is the rest of the
current assignment, and $v$ is the variable on which a split has just
been performed.  To turn these two theorems into the desired
\[
\phi_0,\Delta\vdash \holtxt{F}
\]
we will use the rule of inference \ml{DISJ\_CASES}:
\[
\infer{\Gamma \cup \Delta_1 \cup \Delta_2 \vdash \phi}{
  \Gamma \vdash \psi \lor \xi &
  \Delta_1 \cup \{\psi\}\vdash \phi &
  \Delta_2 \cup \{\xi\} \vdash \phi
}
\]
and the theorem \ml{BOOL\_CASES\_AX}:
\[
\vdash \forall t.\;(t = \holtxt{T}) \lor (t = \holtxt{F})
\]

We can put these fragments together and write the top-level
\ml{CoreDPLL} function, in Figure~\ref{fig:coredpll}.
\begin{figure}[htbp]
\begin{holboxed}
\begin{verbatim}
fun CoreDPLL form = let
  val initial_th = ASSUME form
  fun recurse th = let
    val c = concl th
  in
    if c = boolSyntax.T then
      mk_satmap th
    else if c = boolSyntax.F then
      Unsat th
    else let
        val v = find_splitting_var c
        val (l,r) = casesplit v th
      in
        case recurse l of
          Unsat l_false => let
          in
            case recurse r of
              Unsat r_false =>
                Unsat (DISJ_CASES (SPEC v BOOL_CASES_AX) l_false r_false)
            | x => x
          end
        | x => x
      end
  end
in
  case (recurse initial_th) of
    Unsat th => Unsat (CONV_RULE (REWR_CONV IMP_F_EQ_F) (DISCH form th))
  | x => x
end
\end{verbatim}
\end{holboxed}
\caption{The core of the DPLL function}
\label{fig:coredpll}
\end{figure}

All that remains to be done is to figure out which variable to
case-split on.  The most important variables to split on are those
that appear in what are called ``unit clauses'', a clause containing
just one literal.  If there is a unit clause in a formula then it is
of the form
\[
\phi \land v \land \phi'
\]
or
\[
\phi \land \neg v \land \phi'
\]
In either situation, splitting on $v$ will always result in a branch
that evaluates directly to false.  We thus eliminate a variable
without increasing the size of the problem.  The process of
eliminating unit clauses is usually called ``unit propagation''.
Unit propagation is not usually thought of as a case-splitting
operation, but doing it this way makes our code simpler.

If a formula does not include a unit clause, then choice of the next
variable to split on is much more of a black art.  Here we will
implement a very simple choice: to split on the variable that occurs
most often.  Our function \ml{find\_splitting\_var} takes a formula
and returns the variable to split on.
\begin{hol}
\begin{verbatim}
   fun find_splitting_var phi = let
     fun recurse acc [] = getBiggest acc
       | recurse acc (c::cs) = let
           val ds = strip_disj c
         in
           case ds of
             [lit] => (dest_neg lit handle HOL_ERR _ => lit)
           | _ => recurse (count_vars ds acc) cs
         end
   in
     recurse (Binarymap.mkDict Term.compare) (strip_conj phi)
   end
\end{verbatim}
\end{hol}
This function works by handing a list of clauses to the inner
\ml{recurse} function.  This strips each clause apart in turn.  If a
clause has only one disjunct it is a unit-clause and the variable can
be returned directly.  Otherwise, the variables in the clause are
counted and added to the accumulating map by \ml{count\_vars}, and the
recursion can continue.

The \ml{count\_vars} function has the following implementation:
\begin{hol}
\begin{verbatim}
   fun count_vars ds acc =
     case ds of
       [] => acc
     | lit::lits => let
         val v = dest_neg lit handle HOL_ERR _ => lit
       in
         case Binarymap.peek (acc, v) of
           NONE => count_vars lits (Binarymap.insert(acc,v,1))
         | SOME n => count_vars lits (Binarymap.insert(acc,v,n + 1))
       end
\end{verbatim}
\end{hol}

The use of a binary tree to store variable data makes it efficient to
update the data as it is being collected.  Extracting the variable
with the largest count is then a linear scan of the tree, which we can
do with the \ml{foldl} function:
\begin{hol}
\begin{verbatim}
   fun getBiggest acc =
     #1 (Binarymap.foldl(fn (v,cnt,a as (bestv,bestcnt)) =>
                            if cnt > bestcnt then (v,cnt) else a)
                        (boolSyntax.T, 0)
                        acc
\end{verbatim}
\end{hol}

\subsection{Performance}
\label{sec:dpll-performance}

Once inputs get even a little beyond the clearly trivial, the function
we have written (at the top-level, \ml{DPLL\_UNIV}) performs considerably
better than the truth table implementation.  For example, the
generalisation of the following term, with 29 variables, takes
\ml{wrapper} two and a half minutes to demonstrate as a tautology:
\begin{hol}
\begin{verbatim}
   (s0_0 = (x_0 = ~y_0)) /\ (c0_1 = x_0 /\ y_0) /\
   (s0_1 = ((x_1 = ~y_1) = ~c0_1)) /\
   (c0_2 = x_1 /\ y_1 \/ (x_1 \/ y_1) /\ c0_1) /\
   (s0_2 = ((x_2 = ~y_2) = ~c0_2)) /\
   (c0_3 = x_2 /\ y_2 \/ (x_2 \/ y_2) /\ c0_2) /\
   (s1_0 = ~(x_0 = ~y_0)) /\ (c1_1 = x_0 /\ y_0 \/ x_0 \/ y_0) /\
   (s1_1 = ((x_1 = ~y_1) = ~c1_1)) /\
   (c1_2 = x_1 /\ y_1 \/ (x_1 \/ y_1) /\ c1_1) /\
   (s1_2 = ((x_2 = ~y_2) = ~c1_2)) /\
   (c1_3 = x_2 /\ y_2 \/ (x_2 \/ y_2) /\ c1_2) /\
   (c_3 = ~c_0 /\ c0_3 \/ c_0 /\ c1_3) /\
   (s_0 = ~c_0 /\ s0_0 \/ c_0 /\ s1_0) /\
   (s_1 = ~c_0 /\ s0_1 \/ c_0 /\ s1_1) /\
   (s_2 = ~c_0 /\ s0_2 \/ c_0 /\ s1_2) /\ ~c_0 /\
   (s2_0 = (x_0 = ~y_0)) /\ (c2_1 = x_0 /\ y_0) /\
   (s2_1 = ((x_1 = ~y_1) = ~c2_1)) /\
   (c2_2 = x_1 /\ y_1 \/ (x_1 \/ y_1) /\ c2_1) /\
   (s2_2 = ((x_2 = ~y_2) = ~c2_2)) /\
   (c2_3 = x_2 /\ y_2 \/ (x_2 \/ y_2) /\ c2_2) ==>
   (c_3 = c2_3) /\ (s_0 = s2_0) /\ (s_1 = s2_1) /\ (s_2 = s2_2)
\end{verbatim}
\end{hol}
(if you want real speed, the built-in function \ml{tautLib.TAUT\_PROVE} does the above
in less than a second, by using  an external tool to generate the proof
 of unsatisfiability, and then translating that proof back into HOL).

\section{Extending our Procedure's Applicability}
\label{sec:dpll-applicability-extension}

The function \ml{DPLL\_UNIV} requires its input to be universally
quantified, with all free variables bound, and for each literal to be
a variable or the negation of a variable.  This makes \ml{DPLL\_UNIV}
a little unfriendly when it comes to using it as part of the proof of
a goal.  In this section, we will write one further ``wrapper''
layer to wrap around \ml{DPLL\_UNIV}, producing a tool that can be
applied to many more goals.

\paragraph{Relaxing the Quantification Requirement}  The first step is
to allow formulas that are not closed.  In order to hand on a formula
that \emph{is} closed to \ml{DPLL\_UNIV}, we can simply generalise
over the formula's free variables.   If \ml{DPLL\_UNIV} then says that
the new, ground formula is true, then so too will be the original.  On
the other hand, if \ml{DPLL\_UNIV} says that the ground formula is
false, then we can't conclude anything further and will have to raise
an exception.

Code implementing this is shown below:
\begin{hol}
\begin{verbatim}
   fun nonuniv_wrap t = let
     val fvs = free_vars t
     val gen_t = list_mk_forall(fvs, t)
     val gen_t_eq = DPLL_UNIV gen_t
   in
     if rhs (concl gen_t_eq) = boolSyntax.T then let
         val gen_th = EQT_ELIM gen_t_eq
       in
         EQT_INTRO (SPECL fvs gen_th)
       end
     else
       raise mk_HOL_ERR "dpll" "nonuniv_wrap" "No conclusion"
   end
\end{verbatim}
\end{hol}

\paragraph{Allowing Non-Literal Leaves}
We can do better than \ml{nonuniv\_wrap}: rather than quantifying over
just the free variables (which we have conveniently assumed will only
be boolean), we can turn any leaf part of the term that is not a
variable or a negated variable into a fresh variable.  We first
extract those boolean-valued leaves that are not the constants true or
false.
\begin{hol}
\begin{verbatim}
   fun var_leaves acc t = let
     val (l,r) = dest_conj t handle HOL_ERR _ =>
                 dest_disj t handle HOL_ERR _ =>
                 dest_imp t handle HOL_ERR _ =>
                 dest_bool_eq t
   in
     var_leaves (var_leaves acc l) r
   end handle HOL_ERR _ =>
     if type_of t <> bool then
       raise mk_HOL_ERR "dpll" "var_leaves" "Term not boolean"
     else if t = boolSyntax.T then acc
     else if t = boolSyntax.F then acc
     else HOLset.add(acc, t)
\end{verbatim}
\end{hol}
Note that we haven't explicitly attempted to pull apart boolean
negations (which one might do with \ml{dest\_neg}).  This is because
\ml{dest\_imp} also destructs terms \holtxt{\~{}p}, returning
\holtxt{p} and \holtxt{F} as the antecedent and conclusion.  We have
also used a function \ml{dest\_bool\_eq} designed to pull apart only
those equalities which are over boolean values.  Its definition is
\begin{hol}
\begin{verbatim}
   fun dest_bool_eq t = let
     val (l,r) = dest_eq t
     val _ = type_of l = bool orelse
             raise mk_HOL_ERR "dpll" "dest_bool_eq" "Eq not on bools"
   in
     (l,r)
   end
\end{verbatim}
\end{hol}

Now we can finally write our final \ml{DPLL\_TAUT} function:
\begin{hol}
\begin{verbatim}
   fun DPLL_TAUT tm =
     let val (univs,tm') = strip_forall tm
         val insts = HOLset.listItems (var_leaves empty_tmset tm')
         val vars = map (fn t => genvar bool) insts
         val theta = map2 (curry (op |->)) insts vars
         val tm'' = list_mk_forall (vars,subst theta tm')
     in
         EQT_INTRO (GENL univs
                      (SPECL insts (EQT_ELIM (DPLL_UNIV tm''))))
     end
\end{verbatim}
\end{hol}
Note how this code first pulls off all external universal
quantifications (with \ml{strip\_forall}), and then re-generalises
(with \ml{list\_mk\_forall}).  The calls to \ml{GENL} and \ml{SPECL}
undo these manipulations, but at the level of theorems.  This produces
a theorem equating the original input to true.  (If the input term is
not an instance of a valid propositional formula, the call to
\ml{EQT\_ELIM} will raise an exception.)

\section*{Exercises}

\begin{enumerate}
\item Extend the procedure so that it handles conditional expressions
  (both arms of the terms must be of boolean type).
\end{enumerate}

%%% Local Variables:
%%% mode: latex
%%% TeX-master: "tutorial"
%%% End: