Beruflich Dokumente
Kultur Dokumente
Abstract Collaborative Real-time editing has become an essential tool for many distributed
workplaces. We present an introduction to the main algorithms that allow collaborative real-time
editors to achieve their primary goals of controlling concurrency and maintaining document
consistency, whilst also achieving their usability goals. We also present a simple implementation
for collaborative editing of plain text documents.
1
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
I. INTRODUCTION
Since the advent of the Web 2.0 technologies collaborative real-time editing (CRTE)
systems have flourished. Products such as Google Docs and Office365, which allow
collaborators to work together in real-time from different physical locations, have become
commonplace and an essential component of many distributed workplaces.
The essential problems that CRTEs must solve are those of distributed concurrency control
and maintaining correctness and consistency amongst collaborators, or peers.
However, in addition to these essential problems there are a number of human-related
issues impacting CRTEs that do not affect other distributed systems to the same extent. These
usability criteria make the use of more general distributed problem solvers algorithms and
techniques that are widely used in distributed software less capable of achieving these
primary goals.
CRTEs are interactive systems, and need to maintain a high level of liveness. That is, the
system should have a level of responsiveness that is comparable to the regular, non-
collaborative editors that users are used to. Furthermore, this responsiveness should also
apply to changes made remotely by other peers. Changes made by one peer should be visible
in near real-time to all the other peers. If this latter property is not fulfilled, peers changes
would rapidly diverge and a state of confusion would arise amongst collaborators.
These usability requirements exclude the use of, for example, locking and mutual
exclusion techniques. If such techniques were applied to this problem a systems
responsiveness would suffer proportionately to the number of connected users. When
confounded by network latency these strategies would deliver poor usability and an
ineffective product.
The most widespread solutions are found in the family of algorithms known as
Operational Transformation. These algorithms achieve concurrency control, maintain
consistency and correctness and allow systems to remain highly responsive. Most versions of
Operational Transformation employ a further, more general, distributed algorithm, the Vector
Clock, as a means of achieving partial orderings.
We will conduct a brief background survey of Distributed Mutual Exclusion, Matrix
Clock, Snapshot and Operational Transformation algorithms, in addition to a more detailed
discussion and analysis of Operational Transformation and Vector Clocks. Finally, we will
present a simple implementation of a CRTE, using the Operational Transformation and
Vector Clock algorithms.
2
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
3
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
Each node maintains an array RNi[N] where i is the identifier and N is the number
of nodes in the system. This array is present at each node and stores information
of all other nodes in the system.
The algorithm uses a token which contains a queue which contains the nodes that
request for the critical section and an array - LN [N] which contains the latest
sequence number executed by the node.
An incoming request is accepted only is RNi[j] < s where s is the sequence
number of the request, if this condition is not true this request is treated as an
outdated request.
A requesting node i broadcasts request message (i,s) and changes its sequence
number in its array RNi[i].
Receiving nodes check if the request is outdated or not and update there RNi.
When the node holding, the token receives the request and is not in the critical
section it places the sending node in the queue.
This node sends the token to the node on the top of the queue. When the node i
receives this node, it can enter its critical section.
Hence the algorithm requires N-1 request message and one message containing the token
to perform a single mutual exclusion. For the purposes of building a collaborative real
time editor using mutual exclusion was not the best approach as the system should allow
for concurrent updates to the shared document. This problem of concurrent updates was
further solved using operational transform techniques.
B. Matrix and Vector Clocks
1. What is a matrix clock?
In an asynchronous distributed system with multiple nodes, we can use vector clock to
denote the sequence of events including value changes or massage passing. However, the
vector clock could only give limited information about global state from an individual
view. In a matrix clock system, the time is represented by a list of vector clocks. As for
process pk, it maintains a matrix mti[1n,1m] where:
mti[i ,i] denotes the local logical clocks of pi and track the progress of the computation
at process pi.
mti[i ,j] represents the latest knowledge that process pi has about the knowledge of pj
has about the logical local clock of pj. The entire matrix mti denotes pis local view of
the logical global time. (Garg, 2002)
Form one point of view, the matrix clock extends the 1-dimensional vector clock into n-
dimensional stage where n is determined by the number of nodes, or normally we say
processes. From another point of view, matrix clock can be generalised as a set of vector
clocks, and is a more sophisticated algorithm for capturing chronological and causal
relationship in a distributed system. In general, matrix clock can deliver much more
information, but it also increases computation and storage consumption as well. One of the
task while implementing a matrix clock is to leverage the trade-off between more
information and higher complexity.
2. The implication of matrix clock
4
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
C. Operational Transformation
Here we offer a brief introduction to the operational transformation algorithm. We will
describe its origin and basic form
The first collaborative real-time editor is widely considered to be that which was
demonstrated by Douglas Engelbart in 1968. This presentation The Mother of all Demos
demonstrated many features which have since become ubiquitous parts of personal
computing. The mouse, graphical interfaces, video conferencing and hyperlinks were also on
show. Like most of these other functionalities, collaborative editing took a long time to make
it to widespread personal computing.
Operational Transformation was first described by Ellis and Gibbs1 in 1989. The
algorithm they described, known as dOPT (distributed operational transformation), was
implemented in their software GROVE (Group Outline Viewing Editor). Ellis and Gibbs
identified the concurrency control problem related to CRTEs and noted that more generic
approaches such as locking were unsuitable for CRTE implementations. The solution that
was proposed resolved conflicts, preserved intention and causality and maintained
consistency throughout the distributed versions of the shared document.
Their solution is centered around the idea that every change can be expressed as a
combination of two types of atomic operation. A user either inserts a chunk of text or deletes
5
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
a chunk of text, and the state of the document can be expressed as a log, or history, of these
operations.
Insert( integer:index, string:value ) Delete( integer:index, integer:length )
Each change is logged to an operation history as one or more of these operations, and
those operations are broadcast to peers. Upon receipt, each peer checks its own operation
history, and transforms the incoming operation against any concurrent operations that have
been performed locally. The transformed operation is then applied to the local document and
written to the local operation history.
The figure below demonstrates a comparison between two sequences of events one that
transforms received operations and one which does not.
A B A B
aaaccc cccbbb
aaaccc cccbbb
Figure 1: Comparison of concurrent insert operations with and without Operational Transformation
We see that where an insert operation is received and applied without transformation,
peers documents diverge and consistency is lost. Similarly, a delete operation will also result
in divergence. However, when received operations are transformed, peers documents
maintain their consistency. It is worth noting that while consistency is maintained in each
peers document, their individual operation histories will contain subtle differences but
differences will still result in a consistent state between peers.
The basic form of the transform function is quite simple. Below, we see the transformation
of the received operation Or against the history operation Oh.
6
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
if Oh.operation == delete:
Or .index -= Oh.length
if Oh.operation == insert:
Or .index += Oh.value.length
return Or
When an operation is transformed, its index its position in the text is compared to
that of the operation it is transforming against. The received operation needs to be
transformed if its index is greater than the index of the historical operation. If its index is less,
the historical operation has no effect. These two cases result in a consistent and correct state
between peers, but there the final case, where the index is same, presents a dilemma. The two
peers have tried to insert, or delete, at the same index. This gives the dilemma of having to
decide who goes first. The solution is to break this tie using an agreed priority. A standard
way to do this is to use the peers ids as a tie-breaker, but which peer is given priority is not
important. What is important is that this priority and therefore the result of the
transformation and the effect it has on the shared document is consistent for all peers.
Ellis and Gibbs did not present a full proof of correctness, but offered an outline of the
form this proof should take, the problems that must be solved and the properties the algorithm
must maintain in order to be considered correct. These properties are known as the
consistency model.
The main problems that must be solved are divergence and causality-violation, and these
two problems essentially defined the properties of the consistency model: convergence and
causality preservation.
Subsequent work, such as Sun and Ellis2, has shown the correctness of the dOPT algorithm
to be flawed and have proposed that the consistency model be expanded. Indeed, several
different consistency models have been described and applied to numerous variations of the
Operational Transformation algorithm, and we will discuss these models below.
While dOPT and other variations focused on linear documents such as plain text real
world applications and requirements have pushed work into the development of more
sophisticated algorithms, which, while still based on the core ideas of Ellis and Gibbs dOPT,
have adapted to work with rich data structures and the kind of documents that people need to
produce. Davis, Sun and Lu3, for example, discuss rich-text documents which form tree-like
structures based on publishing conventions and semantic meaning, and describe the
generalization of the operational transform to deal with markup languages. It is evident that
such requirements are not only necessary, but are met by the major CRTEs. We will discuss
this approach below.
7
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
D. Snapshot
There are many algorithms and research papers available with various theories describing how
to take snapshots for a distributed system but most of them are trivial. Some of them are not
applicable in the real world and some are incorrect as written by Chandy and Lamport in their
famous and well know paper in distributed snapshots. The reason for incorrectness of these
algorithms is that various concepts of distributed system are not defined properly. Chandy and
Lamports research defines these distributed system concepts. All the research work published
after their paper either extends their idea about distributed snapshots or is a variation of their
algorithm. For example, Chandy and Lamport's paper is applicable to FIFO (First in first out)
and asynchronous system and using this algorithm Friedemann Mattern has published an
algorithm which is applicable to non-FIFO channels. He has optimized the algorithm using
GVT (Global Virtual Time).
Chandy and Lamport's algorithm forms a baseline for snapshot algorithms. The main
prerequisite to these algorithms is that it should not interrupt the actual system and a correct
algorithm always captures all process states as well as messages in all channels. Process states
can be anything based on the type of application. Also, there should not be any single point of
operation, this means that any process in the system can start capturing a snapshot.
In the Chandy-Lamport algorithm, any process that wants to start on capturing a system
snapshot will first records its own states, and after that, it sends marker messages to other
processes and will also start to listen for marker messages on which it already sent. When
another process receives a marker message, it records its own state and sends marker message
to all other processes including the one from which it received. When the first process receives
marker messages from all other processes, it stops recording channels. So, after the end of the
algorithm, we get pieces of the snapshot which we can put together to create one single
snapshot.
Here is one simple example of how Chandy-Lamport algorithm works.
8
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
Matrix clock is a generalization of the notion of vector clock. Apart from having the latest
state of its local process, it also contains the current state of other processes known by
itself. The sending and receiving events corresponding to certain message-passing action
can be unambiguously matched through matrix clock. Matrix clock allows a process to
establish a lower bound on what other nodes know, which means it can acknowledge if the
incoming information is obsolete or not. On the other hand, matrix clock is also costly
implement due to it requires much higher storage and communication overheads.
2. Example of VC and MC
In terms of vector clock, there are two types of operation needs to be timestamped: the
operation sent from editor when the user changes the content on the editor; and the
operation from other peers when there are changes happened on other peers local
document.
9
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
Once the server receives an operation from the editor, the local document needs to be
updated according to this operation. The server node will increment current vector clock
and timestamp this operation, then insert it to the queue. Next server will broadcast this
operation with latest vector clock to other peers to request other peers changes their local
document.
When a server receives an operation from other peers, it firstly increments its own vector
clock, and then merges the vector clock on this incoming operation and its local vector
clock. The incoming operation with new timestamp will also be inserted to the queue.
Before writing all the operations in the queue into local document, the server will check
the concurrency issues. If one operation has no concurrent conflict, it will be directly
written into local file. But fi there are concurrent operations, server will implement
Operational Transformation algorithm to resolve those conflicts and then write them into
local file.
What would MC look like in a CRTE system
The implementation of matrix clock shares most of similarities with vector clock. The
server will send and receive operations timestamped by matrix clock, and increment,
merge and compare the matrix clock in the same way with vector clock.
In the context of having a collaborative real-time editor, all the operations will be
broadcasted, which implies that each operation will be received by all peers at the end. In
this sense, matrix clock seems to be redundant. For example, matrix clock piggybacks an
information which is process i knows what process j knows about the system, yet the
knowledge of pi will always be the same the pj due to pi and pj both received previous
operations from other peers in the system. In another word, matrix clock doesnt
contribute any useful information to one peers, in addition it highly increases the
complexity of computation and the volume of data to transmit between peers.
B. Application Domains and Future Directions
One typical application of vector clock and matrix clock is system of asynchronous
distributed message-passing. Vector clock are widely used in areas like checkpointing,
maintaining the consistency of duplicated files, termination detection and debugging. Matrix
clock is more likely to be adopted in protocols that should discard obsolete information, such
as distributed database and replicated log.
Given by two different level of knowledge of the whole system, the purpose of these two
clock methods is to achieve the eventual consistency. However, with the size of nodes and
message-passing increasing, the accumulated records of log and history will be impact on the
system performance, in this case, matrix clock will be more preferable due to it tells the
current state of each node in this system. But sword has two edges, in terms of tasks like
debugging or checkpoint, what the user concerns is the exhaustive steps through the entire
process. At this point of view, vector clock becomes more desirable in these situations
because we want to track and trace the history where no information is discarded.
10
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
11
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
type paragraph
children
With this more sophisticated data structure, a more sophisticated addressing system is
required to identify where to perform operations. The required features of a suitable
addressing convention are: locatability; consistency; uniqueness. That is, it must be a
12
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
straightforward task to identify and locate each node, the same address should refer to the
same node for all peers, and each address refers to one node only.
A[]
A[1, 0, 0] A[1, 0, 1]
We now consider the adapted set of operations, Insert, Delete and Change.
Insert and Delete operations are referred to as structural operations. They change the
structure of a tree. The new operation Change is not structural, but rather is a mutation. The
data contained with a node changes without altering the structure of the tree.
Insert and Delete in this model share a new set of parameters to replace the traditional
index parameter. For the functions Insert(N, n, M, T) and Delete(N, n, M) N is the address of a
node, n is the nth child of N, and M is the name of the node. The additional parameter T for
an insertion is the type of the node.
The function Change(N, k, f,) will alter node N, so that the value v for property with key
k is altered to f(v). Thus, an arbitrary number of transitions can be applied on the basis of the
transition function f(). This technique allows the algorithm to loosely couple mutations and
operations, thereby keeping the operational transformation as simple as possible, while
allowing the system to be as extensible as possible.
The consistency model for this enhanced algorithm is similar to existing consistency
models for other operational transformation algorithms. The system must maintain
convergence, causality preservation and intention-preservation.
13
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
V. IMPLEMENTATION DETAILS
A. Purpose and Scope
The purpose of this implementation is to develop working models of the Operational
Transformation and Vector Clock algorithms. A correct implementation of these two
algorithms should result in a consistent and correct CRTE.
Though boiler plate code is required to provide a framework for these implementations,
we will endeavour to keep this scaffold to a bare minimum. For example, though the system
needs to cummunicate with an arbitrary number of peers, we will limit any process of peer
discovery to the minimum required to connect those peers. In practice, this means a manually
defined list of peers, all of which must be present to achieve proper operation of the system.
Likewise, error handling is minimal, and communication is conducted via synchronous
http rather than the preferred asynchronous http that a real world system would employ.
B. System Overview
Though many CRTE systems such as Google Docs use a centralized authority, this
system is a fully decentralized and distributed network of peers. Each peer in this network
maintains its own copy of the shared document and a correct implementation will result in
each of these documents being identical.
14
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
Each peer contains two components: Client and Server. The former is a simple text editor
that the user accesses in a web browser and which communicates with the latter via
asynchronous http. The server itself is a simple http server constructed using the Python
Flask library. This server communicates with its client and other peers, and reads and writes
plain text and JSON to the file system.
Front Operation
Controller History
Observer
C. System Description
Below we describe the systems components.
Client
The client is a simple html page, index.html, containing a text area where the user edits the
shared plain text document. This html initializes with two javascript modules:
plainTextEditor.js and observer.js. Both modules use the javascript module pattern. The
former initializes an html textarea, and the latter observes that textarea for changes, sends
changes to the server and receives changes from the server.
Server
The server is a simple Python application, which is designed with an MVC architecture
and which uses a Flask http server in a Front Controller pattern. Thus, all requests are
intercepted by the front controller crte.py, before being directed to the relevant controller for
Documents or Peers.
D. System Interaction
The two main sequences of interest to this project. The first is when a peer initiates a
change, and the second is when a peer receives a change. These sequences are described
below.
15
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
1) Initiating changes
When the user makes a change in their browser, that event is detected by the editors
observer. To find a balance between fine granularity and minimizing http requests, the
observer waits until the user pauses before sending the new text to the server. The request is
handed to the Document, which runs a Myer Diff algorithm to find differences between the
stored document and the updated text from the client. The results of the diff are used to create
a series of insert and delete operations. On receiving these operations from the client the
server increments its local vector clock using the increment function, packages it into a
transaction, along with a vector timestamp and the peer id.
This transaction is written to the local operation history and its operations applied to the
document file before it is broadcast to each of the networks other peers.
change()
detect()
POST(text)
update(text)
D = find()
D
update(text)
d = diff(text)
o = build
operations(d)
vt = vector
timestamp()
T=
transaction
(o, vt, pid)
write
history(T)
write
document(T)
broadcast(T)
each
POST(T)
T
T
T
perform(T)
each T op
apply(op)
16
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
2) Receiving changes
Two discrete sequences handle receiving and integrating changes from a remote peer. In
the first, an http request is received containing a Transaction. Once the transaction is
received, the receiving peer increments its own local vector clock and merges it with the
incoming vector clock to have an updated local vector clock. The incoming transaction is
placed into an operation queue, where it waits until the system is ready to deal with it.
The second sequence handles the actual integration. The client polls the server to request
any changes, and the Document is asked to integrate. As each transaction Tq is removed from
the transaction queue its vector timestamp is compared with the operation history to find
concurrent transaction. Then, for each concurrent transaction Tc, Tq is transformed into Tq.
Tq is written to the operation history, applied to the document and each operation is returned
to the client so that changes can be applied to the actual editor.
POST(T)
receive(T)
D = find()
D
receive(T)
queue(T)
poll()
integrate()
D = find()
D
integrate()
while Tq = CT = concurrent
Transactions(Tq)
dequeue()
Tq =
Transform (Tq, CT)
write
history(Tq)
write
document(Tq)
ops += Tq.ops
ops
ops
ops
perform(ops)
each op
apply(op)
17
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
E. Algorithms and Data Structures
1) Operational Transformation
Pseudocode of the major operational transformation functions is presented below.
function CreateChanges(text): {
d= MyerDiff(text, old_text) peer_id: integer,
ops = Operations(d) operations: [
vt = VectorTimestamp() { op: insert, index: integer, value: string },
T = BuildTransaction(ops, vt, pid) { op: delete, index: integer, length: integer }
WriteToLocalDocument(T) ],
WriteToLocalHistory(T) timestamp: [ int1, int1, intn ]
BroadcastTransaction(T) }
function Integrate():
while Tq = Dequeue(TQ):
function TransformOperation(O1, O2):
CT = concurrentTransactionsInHistory()
if O2.operation == delete:
Tq = Transform(Tq, CT):
O1.i -= O2.length
WriteToDocument(Tq)
if O2.operation == insert:
WriteToHistory(Tq)
O1.i += O2.value.length
return O1
Figure 11: Receiving and integrating changes
18
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
2. Vector clocks
Below is the pseudocode for the major vector clock operations and a list of events which should trigger
these operations.
function increment(localvectorclocktuple,index):
return localvectorclocktuple[index+1]
function merge(localvectorclocktuple,peervectorclocktuple):
for i = 0 to size
localvectorclocktuple[i] = max(localvectorclocktuple[i],peervectorclocktuple[i])
return localvectorclocktuple
function compare(localvectorclocktuple,peervectorclocktuple)
for i=0 to size
if( localvectorclocktuple[i]<peervectorclocktuple[i])
return -1
else if ( localvectorclocktuple[i] == peervectorclocktuple[i] )
return 0
return 1
function is_concurrent(localvectorclocktuple,peervectorclocktuple)
return (localvectorclocktuple != peervectorclocktuple)
and compare(localvectorclocktuple,peervectorclocktuple) == 0
transaction = response['transaction']
Broadcast_transaction(transaction)
EVENT 2 : A MESSAGE IS RECEIVED FROM A PEER , CHECK IF INCOMING REQUEST IS FROM A KNOWN PEER
if peers_controller.authorisesIP(request.remote_addr):
transaction = request.json['transaction']
timestamp = tuple(transaction['timestamp'])
response = receive_transaction(request)
19
COMP90020: CRTE: Collaborative Real-time Editing. Braithwaite, Lal, Liu, Thakkar
REFERENCES
1
Ellis, Clarence A., and Simon J. Gibbs. "Concurrency control in groupware systems." In Acm Sigmod Record, vol. 18, no.
2, pp. 399-407. ACM, 1989
2
Sun, Chengzheng, and Clarence Ellis. "Operational transformation in real-time group editors: issues, algorithms, and
achievements." In Proceedings of the 1998 ACM conference on Computer supported cooperative work, pp. 59-68. ACM,
1998.
3
Davis, Aguido Horatio, Chengzheng Sun, and Junwei Lu. "Generalizing operational transformation to the standard general
markup language." In Proceedings of the 2002 ACM conference on Computer supported cooperative work, pp. 58-67. ACM,
2002.
4
Sun, Chengzheng, and Clarence Ellis. "Operational transformation in real-time group editors: issues, algorithms, and
achievements." In Proceedings of the 1998 ACM conference on Computer supported cooperative work, pp. 59-68. ACM,
1998.
5
Ressel, Matthias, Doris Nitsche-Ruhland, and Rul Gunzenhuser. "An integrating, transformation-oriented approach to
concurrency control and undo in group editors." In Proceedings of the 1996 ACM conference on Computer supported
cooperative work, pp. 288-297. ACM, 1996.
6
Lushman, Brad, and Gordon V. Cormack. "Proof of correctness of Ressel's adOPTed algorithm." Information Processing
Letters 86, no. 6 (2003): 303-310.
7
Davis, Aguido Horatio, Chengzheng Sun, and Junwei Lu. "Generalizing operational transformation to the standard general
markup language." In Proceedings of the 2002 ACM conference on Computer supported cooperative work, pp. 58-67. ACM,
2002.
8
Mattern, F., 1989. Virtual time and global states of distributed systems. Parallel and Distributed Algorithms, 1(23), pp.215-
226.
9
Chandy, K.M. and Lamport, L., 1985. Distributed snapshots: Determining global states of distributed systems. ACM
Transactions on Computer Systems (TOCS), 3(1), pp.63-75.
10
Mattern, F., 1993. Efficient algorithms for distributed snapshots and global virtual time approximation. Journal of Parallel
and Distributed Computing, 18(4), pp.423-434.
11
Lai, T.H. and Yang, T.H., 1987. On distributed snapshots. Information Processing Letters, 25(3), pp.153-158.
12
Ricart and Agrawala. " An Optimal Algorithm for Mutual Exclusion in Computer Networks Communications January 1981
of Volume 24 the ACM Number 1
13
.Suzuki and Kasami " A Distributed Mutual Exclusion Algorithm Networks ACM Transactions on Computer Systems, Vol.
3, No. 4, November 1985.
14
Chang, Singhal and Liu " A Dynamic Token-Based Distributed Mutual Exclusion Algorithm Dept. of Computer and
Information Science The Ohio State University
20