\documentstyle[12pt,twoside,psfig,amssymb]{article}
\input{defs-6045}






\newcommand{\poly}{{\Bbb P}}
\newcommand{\RP}{{\Bbb RP}}
\newcommand{\nat}{{\Bbb N}}
\newcommand{\fa}{\forall}
\newcommand{\sig}{\Sigma}
\newcommand{\arr}{\rightarrow}
\newcommand{\pless}{\leq_{\poly}}


\begin{document}

\handout{lecture27}{Notes on Lecture 27 (4/10/92)}{April 15, 1992}

{\bf erratum:} The little slip of the day: In Example~1
of Handout~40, there should be $25 n^2 +2n +6 \sim 25 n^2$.


These lecture notes supplement the part of Handout~33 running up
to the middle of page~8: we define the polynomial class $\poly$
and analyze its pros and cons.


\section{Definition of $\poly$}
Recall the definition:

\begin{definition}
\label{def:polyclass}
A function $f : \sig^* \arr \sig^*$ is in $\poly$ if there exists a polynomial
$p : \nat \arr \nat$, there exists a TM $M$ computing $f$ st:
$$
 (\fa x \in \sig^*)\  M \mbox{ halts in at most } p(|x|) \mbox{ steps}.
$$
A set is in $\poly$ iff its characteristic function $\chi_S$ is itself in $\poly$.
\end{definition}

Recall that $\chi_S$ is defined by the conditions
$
\chi_S= \left\{ 
\begin{array}{ll} 0 & \mbox{ if } x \not \in S,\\
               1 & \mbox{ if } x  \in S. 
\end{array}
       \right.
$

\begin{claim}
$$\poly =  \bigcup_{k\geq 1} \TIME(n^k).$$
\end{claim}

\begin{proof}
Exercise! (Hint: this is easy.)
\end{proof}

Just as ``recursive'' or ``recursively enumerable'' capture
our (two) notions of ``computable'', so being in $\poly$
captures the notion of ``feasibly computable''.

\begin{center}
\begin{tabular}{|l|l|}
intuitive notion & formal definition \\ \hline

computable & recursive; r.e. \\
feasibly computable & $\poly$
\end{tabular}
\end{center}

We provide here some reasons justifying the relevance of this definition.

\begin{reason} $\poly$ is model-independent.
\end{reason}

If $f\in \poly$ in the TM model of computation, then it is also in $\poly$
in any other model of computation, and vice versa. (This result is reminiscent of
the ``Church-Turing'' thesis that we saw in computability).
For example the class $\poly$ is the same for the RAM model of computation
as for the TM model.

\begin{reason} Constant-factor sensitivity to the input size
\end{reason}

This property has a good engineering feel about it. It means that an input
 that is 2 times longer only require $c$ times as much work, for some constant $c$.
For instance if the time function is $p(n)= n^3$ then an input twice as long
requires 8 times as much time to be processed. 

Note though that this reason just expresses that the time depends only on 
the input size. (The fact that it depends on it polynomially is irrelevant
in this reason.)

\begin{reason}
In practice, most polynomials are {\em low}-degree polynomials.
\end{reason}
It is very rare to have running time $T(n)$ such that
$n^3 =o(T(n))$.

\begin{reason}
\label{reason4}
The class $\poly$ is closed under polynomial time reductions.
\end{reason}
This result is the exact correspondent of the result
``recursiveness inherits downwards'' that we saw in the
previous part of the class.

To comment on this reason we first introduce the following definition.
\begin{definition}
$A \pless B$ iff [$\exists f \in \poly$ s.t. $x\in A \mbox{ iff } f(x) \in B$].
\end{definition}

The result given in Reason~\ref{reason4} is then formally restated 
as $$[A\pless B \mbox{ and } B\in \poly] \Rightarrow A \in \poly.$$

For instance, assume that we had a $O(n^k)$ algorithm for $B$. Suppose
also that $f$ runs in time $n^l$. Then deciding $A$ by reducing
to $B$ takes $O(n^l)^k$ time.

\begin{reason}
Non-polynomial lower-bounds on running time (i.e. impossibility results as whether
a fast algorithm can be found) are likely to be meaningful: this captures
the (informal) fact that the class $\poly$ is generous and does not require a very
stringent condition from the function candidate to enter it. 
\end{reason}

We now provide a list of some of the backdraws inherent to the notion of
polynomial computability.
\begin{ccritic}
The running time notion considered in the definition of $\poly$
is a {\em worst-case} notion.
\end{ccritic}

For instance it could be the case that almost all inputs 
of size $n$ would require only time $O(n^3)$ and that some very marginal inputs
(of size $n$) would require exponential time $O(2^n)$. In this case
the best {\em overall} bound would only be $O(2^n)$. An average
performance analysis would provide us with the seemingly more 
meaningful $O(n^3)$ time.

An alternative critic would be that even if they were not ``rare'', the inputs for
which the running time is not polynomial could be of enormous
size (e.g. $n= 2^{2^k}$). Hence, for all practical purpose, within our limited
world, most input sizes would actually be handled in polynomial time. 
(This last critic is not so good in the sense that a {\em finite} set of running times
can always be expressed as a polynomial of the input sizes.)


\begin{ccritic}
By definition the constants are immaterial in the consideration
of whether a function is in $\poly$ or not. But actually
a polynomial like 
$10^{10^{10}} n^{10^{10}}$ is not ``feasible''!
\end{ccritic}

\begin{ccritic}
Some other very useful computational tools are not well handled
by $\poly$. By this, we mean that we implicitly make some very restrictive
assumptions about the nature of the algorithms that are implemented.

For instance, randomization (coin flips) are at times
a very powerful tool in the design of algorithms.
As an example, consider the case of {\em primality testing}:
Given input $x\in \nat$, we must answer whether $x$ is prime or composite.
The best deterministic algorithm runs in time $O(n^{{\rm log log} n})$.
(Hence this algorithm is {\em not} in $\poly$, even though 
the exponent in $T(n)$ grows so slowly that $T$ is actually very close to polynomial.)

{\em But} there does exist a polynomially computable function $f$ such that:
$$\begin{array}{lcl}
p \mbox{ prime } \Rightarrow |\{r : 0\leq r \leq p-1\ \& \ f(p,r) = 1 \}| = 0 \\
p \mbox{ composite } \Rightarrow |\{r : 0\leq r \leq p-1\ \& \ f(p,r) = 1 \}| \geq p/2 .
\end{array}
$$

Based on this fact we can now design a probabilistic algorithm that acts as follows:
\begin{itemize}
\item pick $r_1, r_2, \ldots, r_{10}$ at random from $\{0, \ldots, p-1\}$ and 
compute all $f(p,r_i)$.
\item output 0 if all of them are 0. Output 1 else (i.e. when at least
one is 1).
\end{itemize}

We see that if $p$ is prime the algorithm always outputs 0 which is
the correct answer. If $p$ is not prime, for each of the random drawing
of $r_i$ the
answer is 1 with probability at least 1/2. Hence the algorithm outputs
1 with probability bigger then $1 - 1/2^{10}$: the probability of
error is at most $1/2^{10}$ i.e. less then 0.001. But
there is nothing magical about 10: for any $k$ we can get a correct
answer with probability of error less then $2^{-k}$.

To model this great type of procedures, theoreticians have invented the class 
${\RP}$ (one-sided Randomized Protocols).
\begin{definition}
$S \in $~${\RP}$ if there exists a randomized algorithm $M$ s.t. for all inputs $x$,
$M$ computes whether $x$ is in $S$, always gives the correct answer 
if $x \in S$, and gives the correct answer with
probability {\em strictly} bigger then 1/2 if $x \not \in S$.
\end{definition}

A major theoretical question is whether ${\RP} = \poly$. Indeed, randomness seems to
help, but no one is truly sure and we are not even sure which way it should go.
\end{ccritic}

\end{document}

