pand and por.
Major Section: PARALLELISM
The evaluation of (and expr1 expr2) returns nil if expr1
evaluates to nil, avoiding the evaluation of expr2. More generally,
the evaluation of (and expr1 expr2 ... exprk) terminates with a return
value of nil as soon as any expri evaluates to nil -- no
exprj is evaluated in this case for j > i. This so-called ``lazy
evaluation'' of and terms can thus save some computation; roughly
speaking, the smaller the i, the more computation is saved.
If the above call of and is replaced by its parallel version,
pand, then there can be even more opportunity for skipping work. The
arguments to pand can be evaluated in parallel, in which case the first
such evaluation that returns with a value of nil, if any, causes the
remaining such evaluations to abort.
Consider the following functions that compute whether a tree is valid (see granularity for a discussion of the granularity form).
(defun valid-tip (x)
(declare (xargs :guard t))
(or (eq x 'A)
(eq x 'T)
(eq x 'C)
(eq x 'G)))
(defun pvalid-tree (x depth)
(declare (xargs :guard (natp depth)))
(if (atom x)
(valid-tip x)
(pand (declare (granularity (< depth 10)))
(pvalid-tree (car x) (1+ depth))
(pvalid-tree (cdr x) (1+ depth)))))
We would like to stop execution as soon as any tip is found to be invalid.
So, when computing the conjunction of terms by using pand, once one of
those terms evaluates to nil, the computations for the other terms are
aborted and the pand call returns nil. By using pand, we can
in principle attain a speedup factor greater than the number of available
cores.
The concept of early termination also applies to por, except that early
termination occurs when an argument evaluates to non-nil.