<html>

<head><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- MyFirstUnitAd -->
<ins class="adsbygoogle"
     style="display:inline-block;width:970px;height:250px"
     data-ad-client="ca-pub-5778386704669218"
     data-ad-slot="1503492166"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>DFA</title>
</head>

<body>



<p align="center"><span lang="en-ca"><font size="6" color="#FF0000"><b>Reduce&amp;Minimize</b></font></span></p>

<div align="left">
  <pre><b><font color="#ff0000" size="5">A.<span lang="en-ca">First</span> Edition</font></b></pre>
</div>
<div align="left">
  <pre><b>This is <span lang="en-ca">my third edition of </span></b><span lang="en-ca"><b>Reduce, which has now ability to minimize DFA first.</b></span></pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">B</span>.<span lang="en-ca"><a name="problem"></a>The problem</span></font></b></pre>
</div>
<div align="left">
  <pre><b><span lang="en-ca">I feel unsatisfied with the code. It is ugly! However, I don't have enough energy to make a perfect design.</span></b></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>In order to translate the &quot;Transition Diagram&quot; into &quot;Regular Expression&quot;, you need to eliminate all nodes except</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>the start and final ones. 1. Find out all inward and outward arrows and then replace the node by combining each</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>inward starting node with each outward ending node. Their expressions should be concatenated.</b></span></pre>
</div>
<div align="left">
  <b><font color="#ff0000" size="5"><span lang="en-ca">C</span>.<span lang="en-ca">The
  </span></font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>idea of 
  program</b></font></span></div>
<pre><span lang="en-ca"><b>This edition add a new class Minimize which try to find the equivalent nodes in DFA. I have not got time to write</b></span></pre>
<pre><span lang="en-ca"><b>merge function which should be job for next version.</b></span></pre>
<pre><span lang="en-ca"><b>In the class Minimize, I almost have to extract all five parts of a DFA again: Sigma, Q, Delta, F except S is not</b></span></pre>
<pre><span lang="en-ca"><b>necessary at current stage. The algorithm is just what Dr. Ford described in lecture. I originally try to optimize</b></span></pre>
<pre><span lang="en-ca"><b>the algorithm, then realized that it even add more coding job. So, I retained to original algorithm.</b></span></pre>
<div align="left">
  <pre><b><font color="#ff0000" size="5">D.<span lang="en-ca"><a name="Method"></a>The </span>major functions</font></b></pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">C</span>.</font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>Further improvement</b></font></span></pre>
</div>
<div align="left">
  <pre><b><span lang="en-ca">I don't bother to check the result since it is too complicated. So, I have no idea if it is correct or not.</span></b></pre>
</div>
<pre>#include &lt;iostream&gt;
#include &lt;fstream&gt;

using namespace std;

const int MaxStateCount=20;
const int MaxSymbolCount = 5;
enum States
{InBound, OutBound, IsLoop};

enum FinalArrow
{StartLoop, StartFinal, FinalStart, FinalLoop};

struct Function
{
	int domain;
	char* expr;
	int range;
	bool isStart;//means the domain is start
	bool isFinal;//means the range is final	
};

class Minimize
{
private:
	Function* pRules;
	char* symbols[MaxSymbolCount];
	int rulesCount;
	int stateCount;
	int symbolCount;
	int rulesTab[MaxStateCount][MaxSymbolCount];
	bool stateTab[MaxStateCount][MaxStateCount];
	int findStr(char* string);
	bool compareState(int i, int j);
	bool isFinal(int state);
public:
	void initialize(Function* inputRules, int rulesSize);
	void doMinimize();
	void display();
};


class Reduce
{
private:
	Minimize min;
	char privateBuffer[512];
	Function rules[30];
	Function temp[30];
	int tempCount;
	int size;
	int inCount;
	int outCount;
	int loopCount;
	//this record the three type arrow(inbound,outbound, loop) for a particular node
	int buffer[3][30];					  	
	bool findStates(int state);
	bool findShortCut(int state);
	void replace(int state);
	void copyFunction(Function* target, Function* source, bool toClear=false);
	void generate();
	void moveRule(int state);
//	bool notAffected(int index);
	void clearState();
	void addFunction(int index);
	void getExpr();
	void copyStr(char* target, const char* source);
	char* getFinalExpr(char str[][256]);
	char* star(const char* source);
	char* dot(char* target, const char* source);
	char* plus(char* target, const char* source);
public:
	void setParam(Function**theRule, int theSize);
	void readRules(const char* fileName);
	void beginReduce();
	void doMinimize();

};

int main()
{
	Reduce R;
	//you need to copy my input file to your local C:
	R.readRules(&quot;c:\\newrule.txt&quot;);
//	R.beginReduce();
	R.doMinimize();
	
	return 0;
}

bool Minimize::isFinal(int state)
{
	for (int i=0; i&lt;rulesCount; i++)
	{
		if (pRules[i].range==state+1)
		{
			return pRules[i].isFinal;
		}
	}
	return false;
}

void Minimize::display()
{
	for (int i=0; i&lt;stateCount; i++)
	{
		for (int j=0; j&lt;stateCount; j++)
		{
			if (i!=j&amp;&amp;!stateTab[i][j])
			{
				cout&lt;&lt;&quot;(&quot;&lt;&lt;i+1&lt;&lt;&quot;,&quot;&lt;&lt;j+1&lt;&lt;&quot;) &quot;;
			}
		}
	}
}


bool Minimize::compareState(int i, int j)
{
	int first, second;
	for (int sym=0; sym&lt;symbolCount; sym++)
	{
		first = rulesTab[i][sym];
		second = rulesTab[j][sym];
	
		if (stateTab[first][second])
		{
			return true;
		}	
	}
	return false;
}


void Minimize::doMinimize()
{
	bool findNew=false;
	do 
	{
		findNew = false;
		for (int i=0; i&lt;stateCount; i++)
		{
			for (int j=0; j&lt;stateCount; j++)
			{
				if (i!=j&amp;&amp;!stateTab[i][j]&amp;&amp;compareState(i, j))
				{
					stateTab[i][j] = true;
					stateTab[j][i] = true;
					findNew=true;
				}

			}
		}
	}
	while (findNew);
}

int Minimize::findStr(char* string)
{
	for (int i=0; i&lt;symbolCount; i++)
	{
		if (strcmp(string, symbols[i])==0)
		{
			return i;
		}
	}
	return -1;
}

void Minimize::initialize(Function* inputRules, int rulesSize)
{
	pRules = inputRules;
	rulesCount = rulesSize;
	stateCount = 0;
	symbolCount =0;
	int symbolIndex;
	//count state, symbols, and translate diagram into matrix
	for (int i=0; i&lt;rulesCount; i++)
	{
		if ((symbolIndex=findStr(pRules[i].expr))&lt;0)
		{
			symbols[i] = new char[strlen(pRules[i].expr)+1];
			strcpy(symbols[i], pRules[i].expr);
			symbolCount++;
		}
		//assume all index of state is continual
		if (pRules[i].domain&gt;stateCount)
		{
			stateCount= pRules[i].domain;
		}
		if (pRules[i].range&gt;stateCount)
		{
			stateCount = pRules[i].range;
		}
		//this is the rules translated into matrix,
		if (symbolIndex&lt;0)
		{
			symbolIndex = symbolCount-1;
		}
		rulesTab[pRules[i].domain-1][symbolIndex] = pRules[i].range-1;	
	}
//	stateCount++;//this is the count
	//write final states as marked, initialize all others to be false
	for (i=0; i&lt;stateCount; i++)
	{
		for (int j=0; j&lt;stateCount; j++)
		{
			stateTab[i][j]=false;
		}
	}
	for (i=0; i&lt;stateCount; i++)
	{
		bool toMark=isFinal(i);
		for (int j=0; j&lt;stateCount; j++)
		{	
			//assume default is false by initialize
			if (i!=j&amp;&amp;toMark)
			{
				stateTab[i][j]= true;
				stateTab[j][i]= true;
			}	
		}
	}
}

char* Reduce::star(const char* source)
{
	if (source==NULL)
	{
		return NULL;
	}
	strcpy(privateBuffer, &quot;star(&quot;);
	strcat(strcat(privateBuffer, source), &quot;)&quot;);
	return privateBuffer;
}

char* Reduce::dot(char* target, const char* source)
{
	if (source!=NULL)
	{
		if (target==NULL)
		{
			strcpy(target, source);
		}
		else
		{
			strcat(strcat(target, &quot;.&quot;), source);
		}
	}
	
	return target;
}

char* Reduce::plus(char* target, const char* source)
{
	if (source==NULL)
	{
		return target;
	}
	strcat(target, &quot;+&quot;);
	return strcat(target, source);
}


char* Reduce::getFinalExpr(char str[][256])
{
	//the formula is: star(r1).r2.star(r4+r3.star(r1).r2)
	char exp[512];
	char buf[512];
	strcpy(exp, str[FinalStart]);//r3
	dot(exp, star(str[StartLoop]));
	dot(exp, str[StartFinal]);//r3.star(r1).r2
	dot(exp, str[FinalLoop]); //exp+r4, reversed
	strcpy(buf, star(exp));
	strcpy(exp, str[StartLoop]);//exp=r1
	strcpy(exp, star(exp));//star(r1);
	dot(exp, str[StartFinal]);//exp.r2
	dot(exp, buf);
	strcpy(privateBuffer, exp);
	return privateBuffer;
}


void Reduce::copyStr(char* target, const char* source)
{
//	delete []target;
	target = new char[strlen(source)+1];
	strcpy(target, source);
}

//add a function with index of &quot;index&quot; in rules to &quot;temp&quot;
void Reduce::addFunction(int index)
{
	char str[256];
	//scan to see if there are parallel function already in temp
	for (int i=0; i&lt;tempCount; i++)
	{
		//try to union two expr, if they are parallel
		if (temp[i].domain == rules[index].domain&amp;&amp;temp[i].range==rules[index].range)
		{
			strcpy(str, &quot;(&quot;);
			strcat(str, temp[i].expr);
			strcat(strcat(str, &quot;+&quot;), rules[index].expr);
			strcat(str, &quot;)&quot;);
			delete []temp[i].expr;
			temp[i].expr = new char[strlen(str)+1];
			strcpy(temp[i].expr, str);
			//tempCount don't increment!
			return;
		}	
	}
	//if not found, copy
	copyFunction(&amp;temp[tempCount], &amp;rules[index]);
	tempCount++;
}

void Reduce::doMinimize()
{
	min.initialize(rules, size);
	min.doMinimize();
	min.display();
}

void Reduce::readRules(const char* fileName)
{
	ifstream f;
	int flag;
	char str[256];
	size = 0;
	f.open(fileName, ios::in);
	while (!f.eof())
	{
		f&gt;&gt;rules[size].domain&gt;&gt;str&gt;&gt;rules[size].range&gt;&gt;flag;
		rules[size].isStart = flag==1?true:false;
		f&gt;&gt;flag;
		rules[size].isFinal = flag==1?true:false;
		rules[size].expr = new char[strlen(str)+1];
		strcpy(rules[size].expr, str);
		size++;
	}
}



void Reduce::clearState()
{
	//those three type arrow should be cleared
	for (int i=0; i&lt;inCount; i++)
	{
		delete [] rules[buffer[InBound][i]].expr;
	}
	for (i=0; i&lt;outCount; i++)
	{
		delete [] rules[buffer[OutBound][i]].expr;
	}
	for (i =0; i&lt;loopCount; i++)
	{
		delete [] rules[buffer[IsLoop][i]].expr;
	}
}

void Reduce::copyFunction(Function* target, Function* source, bool toClear)
{
	target-&gt;domain = source-&gt;domain;
	target-&gt;range = source-&gt;range;
	if (toClear)
	{
		delete [] target-&gt;expr;
	}
	target-&gt;expr = new char[strlen(source-&gt;expr)+1];
	strcpy(target-&gt;expr, source-&gt;expr);
	target-&gt;isFinal = source-&gt;isFinal;
	target-&gt;isStart = source-&gt;isStart;
}

void Reduce::moveRule(int state)
{
	for (int i=0; i&lt;size; i++)
	{
		//if not affected
		if (rules[i].domain!=state&amp;&amp;rules[i].range!=state)
		{
			addFunction(i);		
		}
	}
	clearState();
	//copy back from temp to rules, in order for next
	for (i=0; i&lt;tempCount; i++)
	{
		copyFunction(&amp;rules[i], &amp;temp[i]);
	}
	size = tempCount;
}

void Reduce::setParam(Function** theRule, int theSize)
{
	size = theSize;
	for (int i=0; i&lt;size; i++)
	{
		copyFunction(&amp;rules[i], theRule[i]);
	}	
}

void Reduce::replace(int state)
{
	generate();
	moveRule(state);
}

void Reduce::generate()
{
	tempCount=0;
	char str[256];
	int in, out, loop;

	//this handles the trap situation
	if (outCount==0)
	{
		return;
	}
	
	for (int i=0; i&lt;inCount; i++)
	{		
		for (int j=0; j&lt;outCount; j++)
		{
			in = buffer[InBound][i];
			out = buffer[OutBound][j];

			temp[tempCount].domain = rules[in].domain;
			temp[tempCount].isStart = rules[in].isStart;//the start from in
			temp[tempCount].range = rules[out].range;
			temp[tempCount].isFinal = rules[out].isFinal;//final from out
			strcpy(str, rules[in].expr);
			for (int k=0; k&lt;loopCount; k++)
			{
				loop = buffer[IsLoop][k];
				if (k==0)
				{
					strcat(str, &quot;.star&quot;);
					strcat(str, &quot;(&quot;);
				}
				strcat(strcat(str, rules[loop].expr), &quot;+&quot;);
				if (k==loopCount-1)
				{
					//replace '+' with ')'
					str[strlen(str)-1]=')';
				}
			}
			strcat(str, &quot;.&quot;);
			strcat(str, rules[out].expr);
			
			temp[tempCount].expr = new char[strlen(str)+1];
			strcpy(temp[tempCount].expr, str);
			//finished one record
			tempCount++;
		}
	}
}


bool Reduce::findStates(int state)
{
	for (int i=0; i&lt;size; i++)
	{		
		if (rules[i].domain==state||rules[i].range==state)
		{
			return true;
		}
	}
	return false;
}

bool Reduce::findShortCut(int state)
{
	inCount = outCount = loopCount = 0;
	for (int i=0; i&lt;size; i++)
	{
		//exclusiveOr and this is a loop
		if (rules[i].domain==state&amp;&amp;rules[i].range==state)
		{
			//the loop 
			if (rules[i].isFinal||rules[i].isStart)
			{
				return false;
			}
			buffer[IsLoop][loopCount]=i;
			loopCount++;
		}
		else
		{			
			if (rules[i].domain==state)
			{
				//if it is start, cannot remove it.
				if (rules[i].isStart)
				{
					return false;
				}
				buffer[OutBound][outCount]=i;
				outCount++;
			}
			if (rules[i].range==state)
			{
				//if it is final, we cannot remove it
				if (rules[i].isFinal)
				{
					return false;
				}			
				buffer[InBound][inCount]=i;
				inCount++;
			}
		}
	}
	//must both have in and out, however, if there is no outBound, it
	//means it is a trap, should be removed immediately
	if (inCount==0)
	{
		cout&lt;&lt;&quot;Error! unaccessable node!\n&quot;;
		return false;
	}
	else
	{
		return true;
	}
}
			
void Reduce::getExpr()
{
	char str[4][256];	
	str[0][0]='\0';
	str[1][0]='\0';
	str[2][0]='\0';
	str[3][0]='\0';
	int startLoop =0, startFinal=0, finalStart=0, finalLoop=0, singleLoop=0;
	for (int i=0; i&lt;size; i++)
	{
		//loop at start, not at final
		if (rules[i].isStart&amp;&amp;!rules[i].isFinal&amp;&amp;rules[i].domain==rules[i].range)
		{
			//for the first one, copy &quot;star&quot;
			if (startLoop==0)
			{
				strcat(strcpy(str[StartLoop], &quot;star(&quot;), rules[i].expr);
			}
			else
			{
				//for the second or more,
				strcat(str[StartLoop], rules[i].expr);
			}
			strcat(str[StartLoop], &quot;+&quot;);
			startLoop++;
		}
		//there is two directions: one from start to final
		//the other is from final to start!!!
		//this is from start to final!
		//I wonder if there is two of such string? should not???
		//yes, it maybe! for an example, there is originally two 
		//parallel arrows between start and final and no operation has
		//ever been taken, so no merge performed.
		if (rules[i].domain!=rules[i].range&amp;&amp;rules[i].isStart&amp;&amp;rules[i].isFinal)
		{
			//the very first expr, use copy
			if (startFinal==0)
			{
				strcpy(str[StartFinal], rules[i].expr);
			}
			else
			{
				//all other use concat
				strcat(str[StartFinal], rules[i].expr);
			}
			strcat(str[StartFinal], &quot;+&quot;);
			startFinal++;
		}
		//the arrow from final to start
		if (rules[i].domain!=rules[i].range&amp;&amp;!rules[i].isStart&amp;&amp;!rules[i].isFinal)
		{
			if (finalStart==0)
			{
				strcpy(str[FinalStart], rules[i].expr);
			}
			else
			{
				strcat(str[FinalStart], rules[i].expr);
			}
			strcat(str[FinalStart], &quot;+&quot;);
			finalStart++;
		}
		//final loop, but not start loop
		if (rules[i].isFinal&amp;&amp;!rules[i].isStart&amp;&amp;rules[i].domain==rules[i].range)
		{
			//for the first one, copy &quot;star&quot;
			if (finalLoop==0)
			{
				strcat(strcpy(str[FinalLoop], &quot;star(&quot;), rules[i].expr);
			}
			else
			{
				//for the second or more,
				strcat(str[FinalLoop], rules[i].expr);
			}
			strcat(str[FinalLoop], &quot;+&quot;);
			finalLoop++;
		}
		//here is the spcial case: start and final are the same
		if (rules[i].isFinal&amp;&amp;rules[i].isStart&amp;&amp;rules[i].domain==rules[i].range)
		{
			//for the first one, copy &quot;star&quot;
			if (singleLoop==0)
			{
				//we &quot;borrow&quot; this string to express
				strcat(strcpy(str[StartLoop], &quot;star(&quot;), rules[i].expr);
			}
			else
			{
				//for the second or more,
				strcat(str[StartLoop], rules[i].expr);
			}
			strcat(str[StartLoop], &quot;+&quot;);
			singleLoop++;
		}
	}
	//overwrite &quot;+&quot; with &quot;)&quot;
	if (singleLoop&gt;0)
	{
		str[StartLoop][strlen(str[StartLoop])-1]=')';
		cout&lt;&lt;str[StartLoop]&lt;&lt;endl;
	}
	else
	{
		if (startLoop&gt;0)
		{
			str[StartLoop][strlen(str[StartLoop])-1]=')';
		}
		if (startFinal&gt;0)
		{
			//must not have more '+'! so write \0 to end
			str[StartFinal][strlen(str[StartFinal])-1]='\0';
		}
		if (finalStart&gt;0)
		{
			str[FinalStart][strlen(str[FinalStart])-1]='\0';
		}
		if (finalLoop&gt;0)
		{
			str[FinalLoop][strlen(str[FinalLoop])-1]=')';
		}
		cout&lt;&lt;getFinalExpr(str)&lt;&lt;endl;
	}
}

void Reduce::beginReduce()
{
	int state=0;
	while (findStates(state))
	{
		if (findShortCut(state))
		{
			replace(state);
		}
		state++;
	}
	getExpr();
}




</pre>
<pre><span lang="en-ca"><a name="result"></a><font size="3" color="#FF0000">The result is like following:</font></span><font size="3" color="#FF0000"> To see input file, <a href="newRule.txt">click here.</a></font></pre>
<div align="left">
<pre><font size="3">//the result is like this:
//(1,5) (2,8) (4,6) (5,1) (6,4) (8,2) Press any key to continue
</font>
</pre>
</div>
<p>กก</p>
<p><span lang="en-ca">**explanation**</span></p>
<p><span lang="en-ca">The state number starts from 1 and in continual mode, (I 
am too lazy to check if there is any number missing.)</span></p>
<p><span lang="en-ca">This result gives the exact one that Dr. Ford showed in 
lecture. </span></p>
<pre>กก</pre>
<pre>	</pre>
<pre></pre>
<pre>			
</pre>

<pre></pre>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                                   
&nbsp;&nbsp;&nbsp; <a href="WhoAmI.htm">                  







                       <img src="picture/back.gif" style="border: medium none" alt="back.gif (341 bytes)" width="32" height="35"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<a href="index.htm"><img src="picture/up.gif" style="border: medium none" alt="up.gif (335 bytes)" width="35" height="32"></a>       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                         
<img src="picture/next.gif" style="border: medium none" alt="next.gif (337 bytes)" width="32" height="35">          


</p>

</body>

</html>