% from 20.3.1989 hk, version 0.03
% revised 5.11.1989 hk, version 0.30
% list processing part 4.1.1990 hk


%\setcounter{chapter}{3}
\chapter{List Processing}

\def\cell#1#2{
\begin{minipage}{2.5cm}
\framebox[2.0cm]{\rule{0.0cm}{0.4cm}#1} \\
\framebox[2.0cm]{\rule{0.0cm}{0.4cm}#2} 
\end{minipage}
}
\def\pcell#1#2{
\begin{minipage}{2.5cm}
\makebox[2.0cm]{\rule{0.0cm}{0.4cm}#1} \\
\makebox[2.0cm]{\rule{0.0cm}{0.4cm}#2} 
\end{minipage}
}
\def\arr{$\longrightarrow$}
\def\ptr{$\bullet$}

In this section we give an introduction to 
list processing.
\index{list processing}

{\bf Definition:} An {\bf atom} is a $\beta$--integer.
A {\bf list} is a finite sequence of atoms and / or lists.
Atoms and lists are {\bf objects}.

In MAS there is a second kind of lists which can also
contain symbols (variables).

{\bf Definition:} An {\bf S--expression} is a 
list where the first element is a symbol
or the first element is an S--expression.
S--expressions may contain further symbols.
\index{S--expression}

Empty lists are denoted by the variable \verb/NIL/.
Other lists are denoted by their elements
separated by commas and enclosed in parenthesis.
E. g. \verb/(1,a)/ denotes the list of the two
elements \verb/1/ and \verb/a/.

The size of lists is only limited by the available
computer memory.


\section{List Construction}

One way to construct a list is by the \verb/LIST/ function.
\verb/LIST/ can be called by any number of arguments
and returns a list of its evaluated arguments.
\index{LIST}
\index{construction}

Example: 
\begin{verbatim}
      x:=LIST(1,2,3,4).         --> (1,2,3,4)
      y:=LIST(1,LIST(2,3),4).   --> (1,(2,3),4)
\end{verbatim}

A second function to construct a list is the 
\verb/COMP/ function (COMPosition).
Its first argument is an object and the second
argument is a list. The object is added as first element 
to the list.
\index{COMP}

Example: 
\begin{verbatim}
      a:=COMP(0,x).             --> (0,1,2,3,4)
      b:=COMP(3,NIL).           --> (3) == LIST(3)
\end{verbatim}

The length of a list can be determined by the
\verb/LENGTH/ function. 
\index{LENGTH}

Two lists can be combined to one list by the
\verb/CONC/ and \verb/CCONC/ functions 
(CONCatenation, Constructive CONCatenation).
CONC and CCONC take two lists as arguments and
return the concatenation of the inputs.
CONC modifies the first list to produce the 
concatenated list and CCONC produces a copy of the
first input. 
\index{CONC}\index{CCONC}

Example: 
\begin{verbatim}
      a:=CCONC(x,y).            --> (1,2,3,4,1,(2,3),4)
      b:=CONC(x,y).             --> (1,2,3,4,1,(2,3),4), but x=b 
\end{verbatim}


\section{List Destruction}

The basic parts of lists are their first element and
the rest list without the first element.
The functions \verb/FIRST/ and \verb/RED/ (for REDuctum = rest)
access these parts.
\index{FIRST}\index{RED}
\index{destruction}

Example: (with the same lists as before) 
\begin{verbatim}
      a:=FIRST(y).              --> 1
      b:=RED(y).                --> ((2,3),4) 
      FIRST(RED(y)).            --> (2,3)
\end{verbatim}

The procedure \verb/ADV/ combines the 
FIRST and RED function. ADV takes a list as first argument;
it returns in the second argument the first element of the list 
and in the third argument the rest of the list.
\index{ADV}

Example: 
\begin{verbatim}
      ADV(y,a,b).               --> (), now a=1, b=((2,3),4)
      a:=a.                     --> 1
      b:=b.                     --> ((2,3),4)
\end{verbatim}

When a new list is constructed while an old list
is processed, the new list is in most cases
in the wrong order. So there is a need to
reverse lists. There are two functions to 
accomplish this: \verb/INV/ (INVerse) and 
\verb/CINV/ (Constructive INVerse).
\index{INV}\index{CINV}

INV modifies the existing list where CINV 
constructs a new list.

Example: (with the same lists as before) 
\begin{verbatim}
      a:=CINV(y).               --> a=(4,(2,3),1) y=(1,(2,3),4) 
      a:=INV(y).                --> a=(4,(2,3),1) y=(1) !!!
\end{verbatim}


\section{List Diagrams}

Lists are stored in the computer in memory cells which
have a first field and a reductum field. These memory
cells are often represented as boxes with two fields:
\index{diagram}

\begin{center}
\cell{FIRST}{RED}
\end{center}

The FIRST field contains objects. The RED field
contains the address (called pointer) of the 
next cell of the list or \verb/NIL/ to 
denote the end of the list.

Example: \verb/LIST(7)./ can be represented as:
\begin{center}
\cell{\verb/NIL/}{7}
\end{center}

\verb/LIST(0,NIL,LIST(1))./ would have the following
representation:
\begin{center}
\cell{\ptr}{\verb/0/}                \pcell{\arr}{}
\cell{\ptr}{\verb/NIL/}              \pcell{\arr}{}
\cell{\verb/NIL/}{\ptr}              \\
\pcell{}{}                           \pcell{}{}
\pcell{}{}                           \pcell{}{}
\pcell{$\downarrow$}{}               \\
\pcell{}{}                           \pcell{}{}
\pcell{}{}                           \pcell{}{}
\cell{\verb/NIL/}{\verb/1/}
\end{center}

The pointers are shown as `\ptr' and `\arr'.
`\ptr' indicates that the field is occupied by a pointer
and `\arr' `points' to the next cell of the list.

Note that in this representation the cells used to
store a list can overlap with other cells:

\begin{verbatim}
       a:=LIST(2).                     --> (2)
       b:=COMP(COMP(0,a),COMP(1,a)).   --> ((0,2),1,2)
\end{verbatim}
The list \verb/b/ contains two pointers to 
the list \verb/a/:
\begin{center}
\cell{\ptr}{\ptr}                   \pcell{\arr}{}
\cell{\ptr}{\verb/1/}               \pcell{\arr}{}
\cell{\verb/NIL/}{\verb/2/}         \\
\pcell{$\downarrow$}{}              \pcell{}{} 
\pcell{}{}                          \pcell{}{}
\pcell{}{$\uparrow$}                \\
\cell{\ptr}{\verb/0/}
\pcell{\arr}{}                      \pcell{\arr}{}
\pcell{\arr}{}                      \pcell{$\cdot$}{}
\end{center}

Some care is needed when such lists are reversed.
If it is done with the \verb/INV/ function, then a 
pointer circle may be constructed:

\begin{center}
\cell{\verb/NIL/}{\ptr}             \pcell{$\longleftarrow$}{}
\cell{\ptr}{\verb/1/}               \pcell{$\longleftarrow$}{}
\cell{\ptr}{\verb/2/}               \\
\pcell{$\downarrow$}{}              \pcell{}{} 
\pcell{}{}                          \pcell{}{}
\pcell{}{$\uparrow$}                \\
\cell{\ptr}{\verb/0/}
\pcell{\arr}{}                      \pcell{\arr}{}
\pcell{\arr}{}                      \pcell{$\cdot$}{}
\end{center}

And if this list is printed one would obtain infinite
output:
\begin{verbatim}
      INV(b).    -->  (2,1,(0,2,1,(0,2, ... infinitely
\end{verbatim}

In such situations it may be required to use
the \verb/CINV/ function to reverse a list.


\section{Exercises}

\begin{enumerate}
\item Construct a list of the numbers $1, \ldots, 100$.
\item Compute the sum of all numbers in this list.
\item Construct an `infinite' list.
\item Write a function which `maps' a function to 
      to the elements of a list and returns the
      list of function results. 
\end{enumerate}

Solution to exercise 1:
\begin{verbatim}
       i:=1. w:=NIL.
       WHILE i <= 100 DO w:=COMP(i,x); i:=i+1 END.
       w:=w.   --> (100, 99, ..., 2, 1)
\end{verbatim}
In the WHILE loop the list \verb/w/ is composed from the 
numbers. The variable \verb/i/ runs from 1 to 100.
The list \verb/w/ is in the descending order. To get the list
in ascending order use \verb/w:=INV(w)./ to reverse the list.

Solution to exercise 2:
\begin{verbatim}
       s:=0. u:=w.
       WHILE u <> NIL DO ADV(u, j,u); s:=s+j END.
       s:=s.   --> 5050
       u:=u.   --> ()
\end{verbatim}
In the WHILE loop each element of \verb/u/ is accessed and
summed in the variable \verb/s/. The sum must be below $\beta$
since \verb/+/ is used as sum operator.

Solution to exercise 3:
\begin{verbatim}
       w:=NIL. i:=0.
       WHILE i = 0 DO w:=COMP(i,w) END.
       --> 
       ** Garbage Collection ... nnn cells, 3 sec.
       ** ... GC completed.
       ...
       ** fatal error: Garbage Collection: too few cells reclaimed.
       (a)bort, (b)reak, (c)continue, (d)ebug, <ENTER> ? break
       ARG: w:=NIL.
\end{verbatim}
In this example the WHILE loop will never terminate
since the variable \verb/i/ is not incremented within the
loop. When the available cell space is consumed, a 
garbage collection takes place. This means that unused
cells (garbage) are searched to become available for
list processing again.
After a while no more or to few free cells are found
and the program encounters a fatal error.
Typing \verb/b/ for break or \verb/<ENTER>/ returns to the 
top level interpreter loop and the \verb/ARG:/ prompt
is displayed. Finally empty the list by \verb/w:=NIL./ to
free the cells for next use.

Solution to exercise 4:
\begin{verbatim}
      PROCEDURE mapcar(f,x);
      (*Map the function f to the elements of 
      the list x. *)
      VAR   y, e, r: ANY;
      BEGIN 
      (*1*) y:=NIL; r:=x;
      (*2*) WHILE r # NIL DO 
                  ADV(r, e, r);
                  e:=f(e); y:=COMP(e,y)
                  END; 
            y:=INV(y); RETURN(y);
      (*9*) END mapcar.
      a:=LIST(1,2,3,4,5).
      ANS: (1 2 3 4 5)
      p:=mapcar(INEG,a).
      ANS: (-1 -2 -3 -4 -5)
\end{verbatim}
\index{mapcar}
Mapcar takes as arguments a function and a list  and applies
the function to all elements of the list. 
In the statement \verb/e:=f(e)/ the parameter f is used as function. 
The so constructed new list is returned. 
In our example the function 
\verb/INEG/, i.e. integer negation is applied to 
\verb/(1 2 3 4 5)/ producing the list  
\verb/(-1 -2 -3 -4 -5)/ of the negated integers. 


\section{Strings}

As already mentioned, character strings are internally
represented as lists of $\beta$--integers.
To make such number lists again visible as character sequence 
the procedure \verb/CLOUT/ can be used 
(Character List OUT). CLOUT writes the output 
to the actual output stream. 
\index{string}
\index{CLOUT}

Example:
\begin{verbatim}
       a:="123".            --> (1,2,3)
       CLOUT(a).            --> 123
       CLOUT("abc").        --> abc
\end{verbatim}

By this list representation of strings it is possible to
use all list processing functions also on strings.

Example:
\begin{verbatim}
       CLOUT(INV("abc")).   --> cba
\end{verbatim}
The string \verb/"abc"/ is first converted to 
the list \verb/(11,12,13)/. Then this list is inverted
and the resulting list is written to the output stream.

\section{Exercises}
 
\begin{enumerate}
\item Write functions \verb/LEFT/ and \verb/RIGHT/, which
      return the left respective right part of a string (list).
      
      \verb/LEFT(A,i)/ returns the $i$ left objects of the list $A$.
      
      \verb/RIGHT(A,i)/ returns the objects of the list $A$ 
      starting from $i+1$.

      So \verb/CONC( LEFT(S,i), RIGHT(S,i) ) = S/ holds. 
\item Write a function \verb/SUBSTR/ which returns a sub--string
      of a string.

      \verb/SUBSTR(A,i,j)/ returns a list of $j$ objects of the list $A$
      starting from $i+1$.
\item Write a function \verb/INDEX/ which determines the
      position of one string within another string.

      \verb/INDEX(a,B)/ returns the position of the list $a$ in the
      list $B$ if $a$ occurs in $B$, otherwise $0$ is returned.
\end{enumerate}

Solution to exercise 1:
\begin{verbatim}
  PROCEDURE left(S,i);
  (*Return the left i elements of the list S.*)
  VAR   s, SP, T, k: LIST;
  BEGIN
  (*1*) SP:=S; T:=NIL; k:=0;
        WHILE (k < i) AND (SP # NIL) DO k:=k+1; 
              ADV(SP,s,SP); T:=COMP(s,T) END;
        T:=INV(T); RETURN(T);
  (*9*) END left.
\end{verbatim}
To obtain the left part of a list it is necessary to copy
the first $i$ elements. 
\index{left}

\begin{verbatim}
  PROCEDURE right(S,i);
  (*Return the right elements of the list S, 
  starting from position i+1.*)
  VAR   SP, k: LIST;
  BEGIN
  (*1*) SP:=S; k:=0;
        WHILE (k < i) AND (SP # NIL) DO k:=k+1; 
              SP:=RED(SP) END;
        RETURN(SP);
  (*9*) END right.
\end{verbatim}
The right part of a list is just the respective reductum 
of the list. No copying is required.
\index{right}

Solution to exercise 2:
\begin{verbatim}
  PROCEDURE sublist(S,i,j);
  (*Return j elements of the list S, 
  starting from position i+1.*)
  RETURN(left(right(S,i),j)) sublist.

  a:=LIST(1,2,3,4,5,6,7,8,9,0).

  left(a,2).      --> (1,2) 
  right(a,7).     --> (8,9,0) 

  sublist(a,3,4). --> (4,5,6,7) 
\end{verbatim}
The substring (list) function can be built by combination of the 
LEFT and RIGHT functions.
\index{substr}\index{sublist}



\section{Complexity}

\label{secCOMPL}
In this section we introduce the basic concepts of 
algorithm complexity. The concepts are applied to 
the list processing algorithms in the next section.

An important point in the 
discussion on algorithms is the time and the space
used to compute a given problem.
\index{complexity}
Time and space are `costs' for the usage of 
an algorithm. 

The definition for the computing time cost function 
is as follows:

{\bf Definition:} Let $I_A$ denote the set of inputs 
for an algorithm $A$ and let {\bf R} be the real numbers. 
Then $t_A : I \mapsto {\bf R}$ 
denotes the computing time function for algorithm $A$.
I.e. $t_A(i)$ $i \in I$ gives the computing time
of algorithm $A$ for input $i$.
When $A$ is clear from the context, we will
shortly write $I$ for $I_A$ and $t$ for $t_A$.

The space cost function $c_A$ is defined analog.

Since the costs may vary for different inputs it is 
convenient to distinguish minimal, average and maximal
cost functions:

{\bf Definition:} Let $I_A$ denote the set of inputs 
for an algorithm $A$ and let $n = \vert I_A \vert$.
Then
\begin{enumerate}
\item the {\em minimal} computing time function is 
      $\tmi = \min\{ t(i) : \ i \in I \}$,
\item the {\em average} expected computing time function is
      $\ta  = \frac{1}{n} \sum_{i \in I} t(i) $, 
\item the {\em maximal} computing time function is 
      $\tma = \max\{ t(i) : \ i \in I \}$.
\end{enumerate}
\index{minimal computing time}\index{average computing time}
\index{maximal computing time}
The following relation holds by definition:
\begin{displaymath}
       \tmi \leq \ta \leq \tma
\end{displaymath}
If $\tmi = \tma$ we denote the 
computing time function by $t$.

Computing time and memory space usage depend on
the data representation, the algorithm and 
on the actual computer and its disks etc.
The computer type is of minor interest, since 
the same algorithm may be implemented on different machines
and we can expect that the computing time varies 
by a constant factor from one machine to another. 
\index{computing time}\index{time}
\index{space}\index{cell}\index{memory} 

How can computing time and space usage be
measured independent of a particular computer architecture ?

The elementary data type in computer algebra is the list.
Therefore it seems naturally to measure 'time' as 
function of the list length of an object.
Memory usage can be measured in terms of cell usage,
which is also a function of list length.

In the following we will assume that 
operations on atoms cost $1$ time unit and that 
no cells are consumed during such an operation.
The time cost for the retrieval of an atom from 
the FIRST field of a cell will be included in the
cost for the operation on the atom. Also the
time to store an atom after an operation will be included in 
the cost for an operation. 
List construction with COMP costs one cell.
The list length of an object $a$ will be denoted by $L(a)$.

For 'simple' algorithms, like those for list processing or
elementary arithmetic,
the minimal and maximal computing time coincide. 
But for other algorithms the times can 
vary by magnitudes.
E.g. polynomials may have many zero coefficients.  
Then the maximal computing time must take into account that 
{\em possibly} all coefficients are non zero 
whereas the minimal computing time must take into account 
that only a certain number of coefficients    
is really non zero.

In complicated cases where the maximum 
computing time is to bad and the average computing time
is not known, also the real computing time on a specific 
machine is taken to get an idea of the 
complexity of the algorithm.

When the computing time functions are determined
constant factors or lower order terms are usually
of minor interest. The big $O$ notation
allows to 'forget' about such details.
$O( f(n) )$ means, that there exists a constant $c$ such that
$O( f(n) ) < c \cdot f(n)$ for all large $n$.
E.g. 
$ 7 \cdot L(a) \sim O(L(a)) $ or
$ L(a) + 3 \sim O(L(a)) $.
But constant and non constant exponents are of interest 
$L(a)^3$, $L(a)^n$ or $L(a)^{L(b)}$.
\index{big $O$ notation}



\section{Algorithms}

In this section we give a more formal summary of
list processing functions. 
We include also information on the complexity of the 
algorithms (see section \ref{secCOMPL}).
The exposition follows \cite{Loos 76}.
\index{list processing}

Let $ \A = \{ x \in {\rm \bf Z} : \ 
              \vert x \vert < \beta \} $ 
be the set of atoms, \\
$ \L = \{ x \in {\rm \bf Z} : \ 
              \beta \leq \vert x \vert \leq \beta+\nu \} $ 
be the set of lists (pointers to cells), \\
$ \O = \A \cup \L $ be the set of objects 
and $ \L_i $ the set of lists of length $ \geq i$.

The left column contains the algorithm specification.
In the right column the type specification of the algorithm 
inputs and outputs and the algorithm function are described. 
Further the algorithm complexity is discussed. 

\begin{deflist}{$a \gets LIST(a_1, \ldots, a_n)$}
\item[$a \gets FIRST(A)$] $a \in \O, A \in \L_1$. 
     $a$ is the first element of the non empty list $A$.
     One cell is accessed, so the computing time is $t = 1$, $c = 0$.     
\index{FIRST}
\item[$A' \gets RED(A)$] $A' \in \L, A \in \L_1$. 
     $A'$ is the reductum of the non empty list $A$, 
     i.e. $A$ without its first element.
     One cell is accessed, so the computing time is $t = 1$, $c = 0$.     
     \index{RED}
\item[$ADV(A, a, A')$] $a \in \O, A' \in \L, A \in \L_1$. 
     $a$ is the first element of the non empty list $A$,
     $A'$ is the reductum of $A$. 
     One cell is accessed, so $t = 1$, $c = 0$.
     \index{ADV}
\item[$B \gets COMP(a,A)$] $a \in \O, A \in \L, B \in \L_1$. 
     $a$ becomes the first element of the non empty list $B$,
     $A$ becomes the reductum of $B$.
     One new cell is made available, so  
     $t = 1$, $c = 1$. (Garbage collection is not taken into account.)
     \index{COMP}
\item[$n \gets LENGTH(A)$] $0 \leq n \in \A, A \in \L$. 
     $n$ is the length of $A$.
     All cells of the list are traversed, so $t = L(A)$, $c = 0$.
     \index{LENGTH}
\item[$A \gets LIST(a_1, \ldots, a_n)$] 
     $a_i \in \O \  (1 \leq i \leq n), n \geq 0, l \in \L$. 
     $A$ is the list of the objects $a_1, \ldots, a_n$.
     $n$ new cells are made available, so the computing time is 
     $t = n$, $c = n$. 
     \index{LIST}
\item[$B \gets INV(A)$] $A, B \in \L$. 
     $B$ is the inverse list of $A$. The cells of 
     $A$ are used to restructure the list $B$. The pointer $A$
     remains unchanged.
     All cells are traversed, so $t = L(A)$, $c = 0$.
     \index{INV}
\item[$B \gets CINV(A)$] $A, B \in \L$. 
     $B$ is the constructive inverse list of $A$. 
     $B$ is a new list, the cells of $A$ remain unchanged.
     $L(A)$ new cells are made available, so 
     $t = L(A)$, $c = L(A)$. 
     \index{CINV}
\item[$A \gets CONC(A_1, A_2)$] $A, A_1, A_2 \in \L$. 
     $A$ is the concatenation of the lists $A_1$ and $A_2$. 
     The cells of $A_1$ are used to built the list $A$
     if $A_1$ is not empty. The pointers $A_1$ and $A_2$ 
     remain unchanged.
     $L(A_1)$ cells are traversed, so $t = L(A_1)$, $c = 0$.
     \index{CONC}
\item[$A \gets CCONC(A_1, A_2)$] $A, A_1, A_2 \in \L$. 
     $A$ is the constructive concatenation of the 
     lists $A_1$ and $A_2$. $A$ is a new list,
     the cells of $A_1$ and $A_2$ are unchanged. 
     $L(A_1)$ new cells are made available, so 
     $t = L(A_1)$, $c = L(A_1)$.
     \index{CCONC}
\item[$t \gets EQUAL(A,B)$] $A, B \in \O$, $t \in \{0, 1\}$. 
     If $A$ and $B$ are equal objects, i.e. 
     atoms or lists with the same structure and same atoms, 
     then $t = 1$ otherwise $t = 0$.
     Maximal the number of cells of the smaller
     object are traversed, minimal one test is required: 
     $\tma = \min\{ EXTENT(A) + 1, EXTENT(B) + 1 \}$, 
     $\tmi = 1$, $\cma = \cmi = 0$.
     \index{EQUAL}
\item[$n \gets EXTENT(A)$] $A \in \O$, $0 \leq n \in \A$. 
     $n$ is the number of cells of the object $A$.
     Overlapping is not counted.
     For $A \in \A$, $n = 0$.
     All cells of the object are traversed, so  
     $t = EXTENT (A)$, $c = 0$.
     \index{EXTENT}
\item[$n \gets ORDER(A)$] $A \in \O$, $0 \leq n \in \A$. 
     $n$ is the maximal nesting level of lists of the object $A$.
     For $A \in \A$, $n = 0$.
     All cells of the object are traversed, so  
     $t = EXTENT (A)$, $c = 0$.
     \index{ORDER}
\end{deflist}

This concludes the summary of list processing functions.
