<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</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 first edition of </span></b><span lang="en-ca"><b>Reduce, which has only a single usage to translate a NFA into regular expression.</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><b><span lang="en-ca">The idea is straight-forward, the algorithm is unefficient.</span></b></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>
<pre>#include &lt;iostream&gt;
#include &lt;fstream&gt;

using namespace std;

enum States
{InBound, OutBound, IsLoop};

struct Function
{
	int domain;
	char* expr;
	int range;
	bool isStart;
	bool isFinal;	
};

class Reduce
{
private:
	Function rules[30];
	Function temp[30];
	int tempCount;
	int size;
	int inCount;
	int outCount;
	int loopCount;
	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();
public:
	void setParam(Function**theRule, int theSize);
	void readRules(const char* fileName);
	void beginReduce();

};

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


void Reduce::addFunction(int index)
{
	char str[256];
	for (int i=0; i&lt;tempCount; i++)
	{
		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);
			return;
		}	
	}
	copyFunction(&amp;temp[tempCount], &amp;rules[index]);
	tempCount++;
}


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++;
	}
}


/*
bool Reduce::notAffected(int index)
{
	rules[index].

	for (int i=0; i&lt;inCount; i++)
	{
		if (rules[buffer[InBound][i]].range==state)
		{
			return false;
		}
	}
	for (i=0; i&lt;outCount; i++)
	{
		if (rules[buffer[OutBound][i]].domain==state)
		{
			return false;
		}
	}
	for (i =0; i&lt;loopCount; i++)
	{
		if (rules[buffer[IsLoop][i]].domain==state)
		{
			return false;
		}
	}
	return true;

}
*/

void Reduce::clearState()
{
	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();
	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;

	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
		if (rules[i].domain==state&amp;&amp;rules[i].range==state)
		{
			if (rules[i].isFinal||rules[i].isStart)
			{
				return false;
			}

			buffer[IsLoop][loopCount]=i;
			loopCount++;
		}
		else
		{			
			if (rules[i].domain==state)
			{
				if (rules[i].isStart)
				{
					return false;
				}
				buffer[OutBound][outCount]=i;
				outCount++;
			}
			if (rules[i].range==state)
			{
				if (rules[i].isFinal)
				{
					return false;
				}
				buffer[InBound][inCount]=i;
				inCount++;
			}
		}
	}
	//must both have in and out
	return (inCount!=0&amp;&amp;outCount!=0);
}
			
void Reduce::getExpr()
{
	char str[256];	
	for (int i=0; i&lt;size; i++)
	{
		//loop at start
		if (rules[i].isStart&amp;&amp;(rules[i].domain==rules[i].range))
		{
			strcat(strcpy(str, &quot;star(&quot;), rules[i].expr);
			strcat(str, &quot;+&quot;);
		}
	}
	str[strlen(str)-1]=')';

	//the main expr
	for (i=0; i&lt;size; i++)
	{
		if (rules[i].domain!=rules[i].range)
		{
			strcat(strcat(str, &quot;.&quot;), rules[i].expr);
		}
	}

	for (i=0; i&lt;size; i++)
	{
		//final loop
		if (rules[i].isFinal&amp;&amp;(rules[i].domain==rules[i].range))
		{
			strcat(str, &quot;.star(&quot;);
			strcat(str, rules[i].expr);
			strcat(str, &quot;+&quot;);
		}
	}
	str[strlen(str)-1]=')';
	cout&lt;&lt;str&lt;&lt;endl;
}

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



</pre>
<pre>	
	
	

</pre>
<pre><span lang="en-ca"><a name="result"></a><font size="3" color="#FF0000">The result is like following:</font></span></pre>
<p>star((b.star(b).a.b+a)).b.star(b).a.a.star((a+b))<br>
Press any key to continue<br>
กก</p>
<p><span lang="en-ca">**explanation**</span></p>
<p><span lang="en-ca">1. I used &quot;star&quot; to represent &quot;keleen star&quot; as I cannot 
print the exponent-like &quot;*&quot;'s.</span></p>
<p><span lang="en-ca">2. I used &quot;.&quot; to show it is a concatenation for better 
reading.</span></p>
<p><span lang="en-ca">3. &quot;+&quot; sign still means the &quot;union&quot;.</span></p>
<p><span lang="en-ca">4. Here is the input file which is the DFA for a language 
over {a,b} such that &quot;baa&quot; is its substring.</span></p>
<p><span lang="en-ca">5. The input file format is like following:</span></p>
<p><span lang="en-ca">&nbsp;&nbsp;&nbsp; Domain&nbsp;&nbsp; Expression&nbsp;&nbsp; 
Range&nbsp; isStart&nbsp; isFinal</span></p>
<p><span lang="en-ca">6. Domain and Range means that the transition functions is 
starting from Domain and ending at Range which is</span></p>
<p><span lang="en-ca">&nbsp;&nbsp;&nbsp; the index of states. The expression is 
the label. When Domain is the initial state, isState is true,</span></p>
<p><span lang="en-ca">&nbsp;&nbsp;&nbsp; indicated by &quot;1&quot;. Otherwise &quot;0&quot;. When 
Range is the final state, isFinal is &quot;1&quot;. Otherwise &quot;0&quot;.</span></p>
<p><span lang="en-ca">7. The input file is named &quot;rules.txt&quot; and stored in place 
of &quot;c:\&quot;.</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>