| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Cellection - A Problem Solving Framework for Computational FunctionsBy P. GopalaKrishna
Cellular automata are discrete dynamical systems that can model many complex systems. They have been proved to be successful in serving as an alternative framework for mathematical descriptions of physical systems. With the inspiration from the success of modeling physical systems we would as well like to provide cellular framework for computational systems also. It should be noted that this is preliminary overview of a much generic framework which is still in development and is subjected to change as improvements are adapted - and we gladly welcome constructive criticism, if any. Relevant source code can be found at [1].
What is cellection framework?Cellection framework is a way of programing the programmable matter. Just the way one solves complex functions with the mechanisms of structured programming methods, cellection framework provides mechanisms for solving the problems using programmable matter methods. What distinguishes the programmable matter is the availability of a massive amount of fine-grained parallelism [2].
So, what follows here?In the following we would examine a way of solving computable functions using cellular automata. We would describe a common framework onto which ordinary functions can be ported and get solved in the cellular automatic way. For this purpose first we identify two kinds of functions. This identification is done as follows.If we consider a function as a mapping from a set of inputs to a set of outputs it is obvious that we can classify the whole set of functions into two classes. In the first class we can place all the Functions whose range is confined just to the values of their inputs (e.g. Find Max, Sort) while the second class could be filled with all those whose range is independent of the values of their inputs (e.g. sin, sqrt) We can understand this classification better by considering the following examples. Consider a function belonging to the first class, say sort. When presented with input {6,2,3} it would produce output {2,3,6} or {6,3,2} depending on its definition. In both cases the output would be a proper subset of the input arguments. On the other hand consider the function sum from the second class of functions. When presented with input arguments {3,5} it would produce output {8} which need not be a subset of the input arguments always.(with few exceptions where one of the arguments is 0. But as a general case we can neglect these special considerations.). These later type of functions like sum, sin etc… are more common in the theories of mathematics and are mostly used in the applications of mathematical analysis while the former class of functions finds their usage mostly in core computer science algorithms and so in the applications of data analysis. While those later class of functions are enjoying a strong standard support from both the theory and practice of mathematicians, the former class is undergoing daily changes as new techniques evolve and are thus far from a standard frame work. It is with this intention of establishing a common frame work for all the computational functions that we progress with the rest of the paper. And it should be noted that this classification we mentioned before is by no means pure and the functions of one class can be freely moved into another class by appropriately modifying its definition. For example, Find Max instead of directly returning the value of the maximum element, it could return the index of that element and thus could be moved into the later class of functions. So, we assume the reader would use appropriate definition as it suits the context. With this word of caution we welcome (back) the reader to the next section. This Framework that we are going to examine contains one simple algorithm implemented with cellular automaton. This algorithm would be compatible with any of the functions whose output forms a subset of the input arguments. However, the algorithm does not work directly upon the input members of the original function. Instead, we establish a common relationship among the input members subjected to the requirements of the output and then we submit this relationship as the input to the cellular framework. This way all that the cellular framework sees is a set of Boolean values typically supplied as a table as shown below.
Function() // The function that we want to
// solve in the cellular automated way
Input: {arg1,arg2…argn}
Output: {argi,argj…} // Output values are actual arguments
where 1<=i,j..<=n
Output: {i,j….} // Output values are indices to argumentsd where 1<=i,j..<=n In the above table true is indicated by T and false by F. The table need not be symmetric. That is, relation(argi,argj) need not be equal to relation(argj,argi). And we have placed a `-` for all the values of main diagonal in the table. They typically represent the values of relation(argi,argi). Since those self relations may not be meaningful always, those places can be filled with any value T or F as they would not affect the outcome. The output of the framework contains indices of the original arguments which when de-indexed gives the desired actual output in terms of the original input arguments. Thus the steps involved in porting an ordinary function onto this cellular framework are:
The actual method by which the framework operates is as follows. As part of the first step, for the given n-input function first we create a cellular automaton with n-cells and tie each cell with one input. Thus each cell of the automaton represents one (and only one) particular member of the input and so the sequence of states through which the cell may traverse depends not just on the states of the local neighbors but also on the nature of the input member which it has chosen to represent. To facilitate this mapping between the input values and the cellular cells, with each cell we maintain an integer that indexes to a particular member in the input array which it is representing. Thus having associated the cells with the inputs this way, we now examine how the automaton progresses. In general, the basic mechanism by which any cellular automaton operates is communication. Two or more cells that lie with in a local neighborhood would communicate among themselves and would affect each other resulting in a change of state. Our cellular framework also uses the same mechanism for its operation. Here the basic unit by which two cells communicate is called a proposal. A proposal is nothing but a list of indices that have agreed upon some condition. Typically the condition would be no more than the relation that we have devised as part of the first step, which we have supplied to the framework in the form of a Boolean table. Considering our one dimensional cellular automata with n cells, all that a cell does at each step is observing the proposal of its immediate right neighbor and copying it onto its own proposal (Cells would be wrapped at the ends). Then the cell would be posed with a choice of either joining the proposal or creating its own version of the proposal from the newly copied proposal. The cell has to take the correct decision based on the contents of the copied proposal and the value of the input argument to which it is indexed. For this it uses the Boolean table that we supplied, as an evaluator function and decides which option it should choose. In case the cell agrees with the newly copied proposal it would join the proposal by appending its index to list of indices that are already present in that proposal and then there ends the matter. However, if the cell does not agree with the newly copied proposal then it would create its own version from the newly copied proposal by discarding all the indices that it does not agree upon. It should be noted that when creating the new version of the proposal from the copied proposal, the copied proposal is not being modified in any way. That is, the copied proposal gets modified only when the cell agrees with it and joins it - otherwise it would be left intact. This new version, the cell would store it in its back proposals queue for later communication. When it observes that there are no more proposals coming from its neighbor it would start publishing them one by one at each time step. This process of generating proposals and publishing them is repeated till there remain no more proposals to generate. Below we present the algorithm implementing the process that we discussed above.
Class _Proposal
{
Vector<int> indices;
Public:
_Proposal () {}
_Proposal (_Proposal &p)
{
*this=p;
}
Bool IsOk (int index, bool Table[n][n])
{
For (int i=0;i<indices. size();i++)
If (Table [indices[i]] [index] ==false)
Return false;
Return true;
}
_Proposal &CreateAValidProposal (int index, bool Table[n] [n])
{
_Proposal Prop;
for(int i=0;i<indices.size();i++)
if(Table[indices[i]][index])
Prop.indices.push_back(indices[i]);
If(Prop.IsIndexPresent(index)==false)
Prop.indices.push_back(index);
Return Prop;
}
Bool operator== (_Proposal &p)
{
if (indices.size()!=p.indices.size())
return false;
for (int i=0;i<indices.size();i++)
if (indices[i]!=p.indices[i])
Return false;
Return true;
}
_Proposal &operator= (_Proposal &p)
{
indices.clear();
For (int i=0; i<p.indices.size ();i++)
indices.push_back(p.indices[i]);
Return *this;
}
Void AppendIndex(int index)
{
indices.push_back(index);
}
bool IsIndexPresent(int index)
{
for(int i=0;i<indices.size();i++)
if(indices[i]==index)
return true;
return false;
}
void ConditionalAssign(_Proposal &p)
{
if(indices.size()<p.indices.size())
*this=p;
}
bool CompletedATurn(int index)
{
if(indices.size()<=0)
return false;
return indices[indices.size()-1]==index;
}
};
Class _Cell
{
Int index;
Int NextBackProposal;
Vector%lt;_Proposal> BackProposals;
Public:
Bool valid;
_Proposal proposal;
_Cell ()
{
Valid=false; NextBackProposal=0;
}
Bool AgreesWith (_Proposal &p, bool Table[n] [n])
{
Return p.IsOk (index, Table);
}
Void JoinTheProposal(_Proposal &p)
{
if(p.IsIndexPresent(index)==false)
p.AppendIndex(index);
}
Bool PickABackProposal()
{
if (NextBackProposal>=BackProposals.size())
Return false;
Proposal=BackProposals [NextBackProposal++];
Return true;
}
void CreateBackProposal(bool Table[n][n])
{
_Proposal backProp;
backProp=proposal.CreateAValidProposal(index, Table);
for(int i=0;i<BackProposals.size();i++)
if(BackProposals[i]==backProp)
return;
BackProposals.push_back(backProp);
}
};
Algorithm ([input] Boolean Table[n] [n])
{
int ElectionTimer=0;
_Cell cells [MAX] [2];
_Proposal ElectedProposal;
cell[n-1][1].valid=true;
cell[n-1][1].proposal.AppendIndex(n-1);
for(int tick=0; ;tick=(tick+1)%2,ElectionTimer++)
{
for(int i=0;i<n;i++)
{
cell[i][tick].valid=false;
if(cell[(i+1)%n][(tick+1)%2].valid==false)
{
Cell[i][tick].valid=cell[i][tick].PickABackProposal();
Continue;
}
cell[i][tick].proposal=cell[(i+1)%n][(tick+1)%2].proposal;
if(cell[i][tick].proposal.CompletedATurn(i))
{
ElectionTimer=0;
ElectedProposal.ConditionalAssign(cell[i][tick].proposal);
Cell[i][tick].valid=cell[i][tick].PickABackProposal();
continue;
}
if(true==cell[i][tick].AgreesWith(cell[i][tick].proposal,Table))
cell[i][tick].JoinTheProposal(cell[i][tick].proposal);
else
cell[i][tick].CreateBackProposal(Table);
cell[i][tick].valid=true;
}
if(ElectionTimer>MAX_ELECTION_TIMER)
break;
}
Return ElectedProposal;
}
In the above algorithm we are using the vector<> objects to hold the back proposals. For those who are not familiar with templates or vector<> objects, a vector<> object is similar to array in the sense that it stores a list of values and we can use the indexing operator [i] to access the ith element. However, unlike arrays, the vector objects can hold elements of any user defined types like class objects etc... and also are provided with additional operations like begin(),end(),push_back(),size() etc.. Here we have used two of them - size() and push_back() in our algorithm. The operation size() returns the number of elements that are currently present in the list or zero if the list is empty. The operation push_back() appends a new element to the end of list. Thus as we can see, whenever a new proposal is generated by a cell, we are adding it to the list of back proposals by using the operation push_back() on the BackProposals vector object. However, before adding any new proposal to back proposals list, we are making sure that it is not already present in the list. Hence at any time during the entire course of algorithm no two proposals in the BackProposals list would be the same. In other words, BackProposals vector never stores duplicates. This makes sure that the algorithm would not suffer from re processing the same proposal twice.
And for the cellular automata, here we are using a simple one dimensional automaton containing n cells. We have implemented the cell as a class object. Each cell object contains the following members.
To understand how this framework can actually be applied to real world problems, we explain the procedure by considering an example problem. Let us consider the maximum clique problem. Here the problem is to find the maximum completely connected component from the given graph. We would be supplied with a set of nodes and edges and we are required to output the largest set of nodes that are completely connected. The required output would be a subset of the set of nodes from the input and so we can apply our framework for this problem.
The process of election can be understood by considering some hypothetical data. Consider the graph shown in the adjacent figure. The execution sequence could be visualized as follows:
Table 1: At time t=0
Table 2: At time t=1
Table 3: At time t=2
Table 4: At time t=3
Table 5: At time t=4
Table 6: At time t=5
Table 7: At time t=6
Table 8: At time t=7, Elected Proposal = {5,4,3}
Table 9: At time t=8, Elected Proposal = {5,4,3}
Table 10: At time t=9, Elected Proposal = {5,4,3}
This is an example where the order of elements is not cared for. However for some problems order in which elements are output is also important. One such problem is sorting. The framework can take care of such problems also. However, proper care should be taken while designing the Boolean relationship table for the input arguments. For example, if we wanted to port the problem of sorting onto our cellular framework then as the first step we need to devise a Boolean relationship among the input numbers such that all the output numbers satisfy the relationship. Consider the problem of sorting a set of n number in ascending order. The output numbers should satisfy the property that output[i]<=output[j] when i<j. Thus we can use this <= as the relationship among the input arguments and can devise the Boolean table accordingly. However, as expressed earlier, the success of this framework completely depends on the wise selection of the Boolean relationship and the construction of the appropriate Boolean table. And devising that relationship is more an art just like creating appropriate classes for an object oriented problem. However, once we are guaranteed that our devised relationship is proper then we can as well be guaranteed that the output would be correct. This we can prove easily by considering the fact that no duplicate proposals are processed and no processed proposal gets reduced in its length (i.e. the number of indices). Thus the algorithm generates only a finite number of proposals and the only modification that ever could be done to a proposal is adding a new index. Hence the two following observations can be made.
But Why Cellection Framework?And finally we are left with one question that one finds still unanswered, why should we use all this? The obvious answers, among others, are:
Hmmm...Anything else?
By P. GopalaKrishna
http://www.geocities.com/krishnapg/
Submitted: 22/11/2003 Article content copyright © P. GopalaKrishna, 2003.
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
All content copyright © 1998-2007, Generation5 unless otherwise noted.
- Privacy Policy - Legal - Terms of Use -