Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
C program to simulate Nondeterministic Finite Automata (NFA)
In this problem, we will create a C program to simulate Non-deterministic Finite Automata (NFA). NFA is a finite state machine that can move to any combination of states for an input symbol, meaning there is no exact state to which the machine will move.
Syntax
struct node {
int data;
struct node* next;
char edgetype;
};
int nfa(node** graph, int current, char* input, int* accept, int start);
Formal Definition of NFA
NFA can be represented by 5-tuple (Q, ?, ?, q0, F) where −
- Q is a finite set of states.
- ? is a finite set of symbols called the alphabets.
- ? is the transition function where ?: Q × ? ? 2^Q (power set of Q because from a state, transition can occur to any combination of states)
- q0 is the initial state from where any input is processed (q0 ? Q).
- F is a set of final state/states of Q (F ? Q).
NFA Representation
Starting state ? 1, Final state (accepting state) ? 4
Example: NFA Simulation Program
This program creates an NFA using adjacency lists and checks if input strings are accepted −
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
int row = 0;
struct node {
int data;
struct node* next;
char edgetype;
} typedef node;
// Adds an edge to an adjacency list
node* push(node* first, char edgetype, int data) {
node* new_node = (node*)malloc(sizeof(node));
new_node->edgetype = edgetype;
new_node->data = data;
new_node->next = NULL;
if (first == NULL) {
first = new_node;
return new_node;
}
first->next = push(first->next, edgetype, data);
return first;
}
// Recursive function to check acceptance of input
int nfa(node** graph, int current, char* input, int* accept, int start) {
if (start == (int)strlen(input))
return accept[current];
node* temp = graph[current];
while (temp != NULL) {
if (input[start] == temp->edgetype) {
if (nfa(graph, temp->data, input, accept, start + 1) == 1) {
return 1;
}
}
temp = temp->next;
}
return 0;
}
// Function to generate binary strings of size n
void generate(char** arr, int size, char *a) {
if (size == 0) {
strcpy(arr[row], a);
row++;
return;
}
char b0[20] = {'\0'};
char b1[20] = {'\0'};
b0[0] = '0';
b1[0] = '1';
generate((char**)arr, size - 1, strcat(b0, a)); // Add 0 in front
generate((char**)arr, size - 1, strcat(b1, a)); // Add 1 in front
return;
}
int main() {
int n;
int i, j;
scanf("%d", &n); // Number of nodes
node* graph[n + 1]; // Create a graph
for (i = 0; i < n + 1; i++)
graph[i] = NULL;
int accept[n + 1]; // Array to store state of vertex
for (i = 0; i < n; i++) {
// Index of vertex, Acceptance state, Number of edges
int index, acc, number_nodes;
scanf("%d%d%d", &index, &acc, &number_nodes);
accept[index] = acc; // Store acceptance
for (j = 0; j < number_nodes; j++) { // Add all edges
int node_add;
int edge;
scanf("%d%d", &edge, &node_add);
graph[index] = push(graph[index], '0' + edge, node_add);
}
}
int size = 1; // Size of input
int count = 0; // Keep count of output strings
if (accept[1] == 1) { // Check for empty string
printf("e<br>");
count++;
}
while (count < 11) {
char** arr;
int power = pow(2, size);
arr = (char**)malloc(power * sizeof(char*));
for (i = 0; i < power; i++)
arr[i] = (char*)malloc(size * sizeof(char));
char a[20] = {'\0'};
generate((char**)arr, size, a); // Generate inputs
for (i = 0; i < power; i++) {
char input[20] = {'\0'};
for (j = 0; j < size; j++) {
char foo[2];
foo[0] = arr[i][size - 1 - j];
foo[1] = '\0';
strcat(input, foo);
// Copy generated string input
}
int result = nfa(graph, 1, input, accept, 0);
// Store result of nfa
if (result == 1) {
printf("%s<br>", input);
count++;
}
if (count == 10)
break;
}
// Free allocated memory
for (i = 0; i < power; i++)
free(arr[i]);
free(arr);
size++; // Increment size of binary string input
row = 0;
}
return 0;
}
Input Format
4 1 0 4 0 1 0 2 1 1 1 3 2 0 1 0 4 3 0 1 1 4 4 1 2 0 4 1 4
Output
00 11 000 001 011 100 110 111 0000 0001
How It Works
- The program uses an adjacency list representation of the NFA graph
- Each node contains the target state and the edge label (0 or 1)
- The
nfa()function recursively explores all possible paths for a given input string - If any path leads to an accepting state after consuming the entire input, the string is accepted
Conclusion
This NFA simulation demonstrates how non-deterministic finite automata can accept multiple paths for the same input. The recursive approach explores all possible state transitions to determine string acceptance in the language defined by the NFA.
