Modifying Dijkstra's Algorithm to an A* implementation - c

I'm in the process of creating a maze simulation of a mouse running through a maze. Dijkstra's algorithm is great and all but isn't particularly effected when cats are involved, which is why I'm trying to modify my existing Dijkstra implementation to an A* search with a heuristic for avoiding the cats which move throughout the maze.
The problem I'm having while I look through some pseudocode is I am unsure of what structures are equivalent or what will I need to introduce to get this working. Can anyone provide any tips or nudges in the right direction?
struct path_node *shortestPath(float A[GsizeSqr][GsizeSqr], int xi, int yi, int xf, int yf)
{
/*
Solves for the shortest path between grid point (xi,yi) and (xf,yf)
on the graph encoded by A using Dijkstra's shortest path method.
The shortest path is returned as a linked list of nodes to be visited.
Keep track of visited nodes, and the predecessor
for each node that has been explored while computing the shortest path.*/
if (xi<0||xi>=Gsize&&yi<0&&yi>=Gsize||xf<0||xf>=Gsize||yf<0||yf>=Gsize)
{
fprintf(stderr,"shortestPath(): Endpoint(s) outside of the graph!\n");
return(NULL);
}
int i, j, pCount, findN, row, col, icnt, stNode, finNode, xcnt, ycnt;
finNode = yf * ceil(sqrt(GsizeSqr)) + xf; //index of start node given its row and col value
stNode = yi * ceil(sqrt(GsizeSqr)) + xi; //index of finish node given its row and col value
int p[GsizeSqr]; //predecessors
int d[GsizeSqr]; //distance from source
int flags[GsizeSqr]; //(0, 1) for unvisited, visited)
int g_score[GsizeSqr];
int f_score[GsizeSqr];
PriorityQueue Q; //Initialize priority queue that stores (priority, key) values
Q = init_heap(GsizeSqr);
path_node *start; //Maintain a pointer to the starting node
start = newPathNode(xi, yi);
start->next = NULL;
//Initialize p and d with infinity and NULL values (note: -1 means null and 1000000 means inf)
for(i=0; i < GsizeSqr; i++){
p[i] = -1;
d[i] = 10000000;
flags[i] = 0;
}
for(i=0; i < GsizeSqr; i++){
node in;
in = create_node(10000000, i);
enqueue(Q, in);
}
//(Note: PQ uses 0 as a sentinel node to make calculating left, right, and parents easier, elements begin at 1)
decrease_priority(Q, stNode+1, 0); //setting start node in PQ.
d[stNode] = 0;
g_score[stNode] = 0;
//For my heuristic, I'm thinking just using manhattan distances between mouse and cat agents
f_score[stNode] = g_score[stNode] + heuristic(xi, yi, xf, yf);
while(Q->heap_size != 1){ //while Q not empty
node u;
u = dequeue(Q);
flags[u.key] = 1;
//For each adjacent node A[u.key][i]
for(i=0; i < GsizeSqr; i++){
if(A[u.key][i] != 0){
findN = find_node(Q, i);
if(flags[i] == 0){ //If it is unvisited and new path distance is shorter
if(findN != 0 && (d[i] >= A[u.key][i] + d[u.key])){ //reset values and update PQ and mark visited
d[i] = A[u.key][i] + d[u.key];
p[i] = u.key;
flags[i] = 1;
decrease_priority(Q, findN, d[i]);
}
}
}
}
}
// Begin selectively filling our LL with values from p[]
icnt = finNode;
appendLL(start, xf, yf);
while(icnt != stNode){
icnt = p[icnt];
xcnt = icnt % (int)ceil(sqrt(GsizeSqr));
ycnt = icnt / (int)ceil(sqrt(GsizeSqr));
appendLL(start, xcnt, ycnt);
}
clean_heap(Q);
return reverseLL(start);
}

You possibly already know this, but the only theoretical difference between A* and Dijkstra's algorithm in terms of best-first search is the cost function f(n). Dijkstra's algorithm is f(n) = g(n) whilst A* is f(n) = g(n) + h(n). Read AIMA for details.
In terms of your code, it currently stores g(n) = A[u.key][i] + d[u.key] in d[i], so you need to change it store g(n) + h(n). You don't need those new g_score and f_score variables, just add the heuristic to the end of that line and the initialization of d[stNode].

Related

Unable to implement Dijkstra's Algorithm using OpenMP in C

I am trying to parallelize Dijkstra using OpenMP, but the program is not working correctly. Sometimes the correct results are displayed while other times I get wrong values, I assume this is because multiple threads are updating the same variable. However I cannot find the source of this problem because I am making shared variable updates inside critical regions. Can someone please help me identify what mistake am I making my assignment is due soon and is this code conceptually correct?
int minDistance(int s,int e,int dist[], bool sptSet[])
{
// Initialize min value
int mini = INT_MAX, min_index;
for (int v = s; v <= e; v++){
if (sptSet[v] == false && dist[v] < mini){
mini = dist[v];
min_index = v;
}
//printf("min_ind %d\n",min_index);
}
return min_index;
}
void Update(int graph[V][V],int s,int e,int hold,int dist[], bool sptSet[]){
for (int v = s; v <= e; v++){
// Update dist[v] only if is not in sptSet,
// there is an edge from u to v, and total
// weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[hold][v] && dist[hold] != INT_MAX && dist[hold] + graph[hold][v] < dist[v]){
dist[v] = dist[hold] + graph[hold][v];
}
}
}
void dijkstra(int graph[V][V],int src)
{
int dist[V]; // The output array. dist[i] will hold the
// shortest
// distance from src to i
bool sptSet[V]; // sptSet[i] will be true if vertex i is
// included in shortest
// path tree or shortest distance from src to i is
// finalized
// Initialize all distances as INFINITE and stpSet[] as
// false
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
// Distance of source vertex from itself is always 0
dist[src] = 0;
int min;
int hold;
int u;
// Find shortest path for all vertices
float start = omp_get_wtime();
#pragma omp parallel shared(hold) private(u) num_threads(3)
{
min=INT_MAX;
int x = omp_get_num_threads();
int chunk = V/x;
int me = omp_get_thread_num();
int startv = me * chunk;
int endv = startv + chunk - 1;
int count = 0;
for (count = 0; count < V - 1; count++) {
// Pick the minimum distance vertex from the set of
// vertices not yet processed. u is always equal to
// src in the first iteration.
u = minDistance(startv,endv,dist, sptSet);
//updating overall minimum
#pragma omp critical
{
if(min > dist[u]){
min = dist[u];
hold = u;
}
}
//waiting for all threads to execute critical section bfr proceeding
#pragma omp barrier
// Mark the picked vertex as processed
#pragma omp single
{
sptSet[hold] = true;
}
#pragma omp barrier
// Update dist value of the adjacent vertices of the
// picked vertex.
Update(graph,startv,endv,hold,dist,sptSet);
min = INT_MAX;
}
}
float end = omp_get_wtime();
// print the constructed distance array
printSolution(dist);
printf("Running time: %f ms\n", (end - start)*1000);
}
----------------THE SERIAL CODE:--------------------
int minDistance(int dist[], bool sptSet[])
{
// Initialize min value
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (sptSet[v] == false && dist[v] <= min)
min = dist[v], min_index = v;
return min_index;
}
// A utility function to print the constructed distance
// array
void printSolution(int dist[])
{
printf("Vertex \t\t Distance from Source\n");
for (int i = 0; i < V; i++)
printf("%d \t\t\t\t %d\n", i, dist[i]);
}
// Function that implements Dijkstra's single source
// shortest path algorithm for a graph represented using
// adjacency matrix representation
void dijkstra(int graph[V][V], int src)
{
int dist[V]; // The output array. dist[i] will hold the
// shortest
// distance from src to i
bool sptSet[V]; // sptSet[i] will be true if vertex i is
// included in shortest
// path tree or shortest distance from src to i is
// finalized
// Initialize all distances as INFINITE and stpSet[] as
// false
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
// Distance of source vertex from itself is always 0
dist[src] = 0;
// Find shortest path for all vertices
for (int count = 0; count < V - 1; count++) {
// Pick the minimum distance vertex from the set of
// vertices not yet processed. u is always equal to
// src in the first iteration.
int u = minDistance(dist, sptSet);
// Mark the picked vertex as processed
sptSet[u] = true;
// Update dist value of the adjacent vertices of the
// picked vertex.
for (int v = 0; v < V; v++)
{
// Update dist[v] only if is not in sptSet,
// there is an edge from u to v, and total
// weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[u][v]
&& dist[u] != INT_MAX
&& dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
}
// print the constructed distance array
printSolution(dist);
}
Dijkstra's algorithm is a good example of an algorithm where the standard formulation is very hard to parallelize. Every step of 1. finding the minimum 2. updating its neighbors depends on the previous. Therefore the best you can do is 1. making that minimum into an OpenMP reduction 2. making the update into a parallel loop. On graphs with small degree this will not give you much speedup. It also means taht your code is not correct: you are trying to parallelize over the outer steps, which are sequential.
However, you don't have to update only the neighbors of that minimum point: you can update all points in every step. That simplifies the code, and reduces overhead. It also does more work, but in wall clock time it may finish slightly faster.

Knuth List Insertion Method in C

I've been reading through the sorting and searching algorithms in Volume 3 of The Art of Computer Programming by Donald Knuth, Second Edition. I came across an algorithm which Knuth calls "list insertion" (A modification on traditional insertion sort) on page 95.
On that page, Knuth concludes that the "right data structure for straight insertion is a one-way, linked linear list.", and that "linked allocation (Section 2.2.3) is ideally suited to insertion, since only a few links need to be changed." However, the MIXAL program (Program L) on page 97 does not appear to utilize a traditional linked linear list structure (a series of nodes linked by addresses). Instead, it appears that the key and the link are stored together in a struct-like structure and these structures are stored in an array called INPUT.
I decided to try to implement this algorithm in C. I have provided Knuth's description of the algorithm, and his implementation in the MIXAL assembly language as reference. I decided to let the keys be the elements, themselves, in the data array, and I put the links in a parallel-like array called links. I say 'parallel-like array' because the size of the links array is one greater than the size of the data array. I did this so I could easily determine the index of the smallest element of the data array by storing it as the first element in the links array. Because of this extra index in links, the indices 0 - (n - 1) of the data array correspond to indices 1 - n of the links array. Each element in the links array corresponds to the index in the data array of the next element in the sorted list.
My question is, is this how this algorithm is supposed to be implemented based on his description, or am I missing something?
int *listInsertion(int data[], int n) {
if (n > 1) {
int i, j, entry;
int *links = (int *) calloc(n + 1, sizeof *links);
links[n] = -1;
links[n - 1] = n - 1;
for (i = n - 2; i >= 0; i--) {
entry = data[i];
for (j = i + 1; links[j] >= 0 && entry > data[links[j]];
j = links[j] + 1)
continue;
if (j == i + 1) {
links[i] = i;
} else {
links[i] = links[i + 1];
links[i + 1] = links[j];
links[j] = i;
}
}
return links;
}
return NULL;
}
I suggest you implement the algorithm with the symbol mentioned by Knuth first.
This will help you figure out the first version quickly.
void insertSort(const int *K, int *L, int n) {
if (n == 1) return;
L[n] = n-1;
L[n-1] = n;
for (int j = n-2; j >= 0; j--) {
int entry = K[j];
int p = L[n];
int q = n;
while(entry > K[p]) {
q = p;
p = L[q];
if (p == n) {
break;
}
}
L[q] = j;
L[j] = p;
}
}
Then you can refactor your first version to enhance it or make it shorter.

quicksort comparison count intermittent results

SOLUTION the solution is unique to my code -- I placed srand(time(NULL)); inside the loop when it should've been placed outside
I'm trying to count the number of comparisons in a quick sort algorithm. I had a recursive version working fine, but it kept seg faulting because I was using large array sizes -- running out of stack space.
So now I've resulted to an iterative approach, and it works. That is, except for my counter for the number of comparisons.
It's returning intermittent results such as...
unsorted: [9][8][7][6][5][4][3][2][1][0]
sorted: [0][1][2][3][4][5][6][7][8][9]
Numer of comparisons: 22
unsorted: [9][8][7][6][5][4][3][2][1][0]
sorted: [0][1][2][3][4][5][6][7][8][9]
Numer of comparisons: 19749794
unsorted: [9][8][7][6][5][4][3][2][1][0]
sorted: [0][1][2][3][4][5][6][7][8][9]
Numer of comparisons: 6088231
my code for the iterative quick sort is...
#include <time.h>
#define BUFLEN 6400
extern int buf[BUFLEN];
extern int quick_count; //comparison count
struct stack {
int stk[BUFLEN];
int top;
};
struct stack s;
void push(int x);
int pop();
void iterative_quick_sort (int buf[], int n) {
int left_ptr, right_ptr, pivot_index, pivot, temp, l, r;
if (n < 2) //case the partitioning has reached the atomic element
return;
r = n - 1;
l = 0;
s.top = -1;
loop: do{
srand(time(NULL));
if ((r - l) == 0)
pivot_index = 1;
else {
pivot_index = rand() % (r - l);
pivot_index += l;
}
pivot = buf[pivot_index]; //pivot holds the value of the pivot element
left_ptr = l;
right_ptr = r;
if ((r - l) != 0 || (r - l) != 1){
while (1) {
while (buf[left_ptr] < pivot){ //loop and increment left_ptr until an element on the left side is larger than the pivot
left_ptr++;
} //now left_ptr holds the index of the value that needs to be swapped with an element from the right side
while (pivot < buf[right_ptr]){ //loop and increment right_ptr until an element on the right side is smaller than the pivot
right_ptr--;
} //now right_ptr holds the index of the value that needs to be swapped with an element from the left side
quick_count++;
if (left_ptr >= right_ptr)
break; //once the pivots reach or overlap each other, break the loop
//perform swap with temporary variable temp
temp = buf[left_ptr];
buf[left_ptr] = buf[right_ptr];
buf[right_ptr] = temp;
}
}
if (l == (n - 2))
break;
else if ((r - l) >= 2){
//goto loop with left side values
push(r);
r = pivot_index + 1;
goto loop;
}
else {
//goto loop with right side values
l = r;
r = pop();
goto loop;
}
}while(1);
}
//cite http://www.sanfoundry.com/c-program-stack-implementation/
void push (int x){
s.top = s.top + 1;
s.stk[s.top] = x;
}
int pop(){
int x = s.stk[s.top];
s.top = s.top - 1;
return x;
}
per request, I've added the function that calls quick sort (Note: quick_count is initialized to zero as a global variable -- used as an extern)
int unsorted_quick[] = {9,8,7,6,5,4,3,2,1,0}; //n = 10
//print unsorted_quick
printf("\nSecond, we sort the following array by using the quick sort algorithm\n");
for (i = 0; i < 10; i++){
printf("[%d]", unsorted_quick[i]);
}
printf("\n");
//fill buf with the unsorted quick array
for (i = 0; i < 10; i++){
buf[i] = unsorted_quick[i];
}
iterative_quick_sort(buf, 10); //call quick_sort()
//print sorted
for (i = 0; i < 10; i++){
printf("[%d]", buf[i]);
}
printf("\nNumber of comparisons: %d\n", quick_count); //print count
You are calling srand(time(NULL)) inside the loop that choose the random pivot. This function must be called once to initialise the state of the random number generator.
The generator needs a starting seed which is set by calling srand(). Then, given the seed, each subsequent call to rand() will give you a random number in a reproducible sequence.
Starting from the same seed you will get the same random sequence.
The problem is that you set the seed in the loop and the seed is the same number so you will always get the same "random" value. This happens because time(NULL) is taken from current time in seconds which means that the random number it's the same in the same second.
You must put it before the loop: do {
Here there is a nice explanation of what is happening: Problems when calling srand(time(NULL)) inside rollDice function
And also here: srand() — why call it only once?

I'm trying to store path in Dijkstra's algorithm

I'm trying to store the path Dijkstra's does when it calculates shortest path to every vertice from the source. This is currently what I'm doing right now but I'm struggling with how to actually store the path. I was hoping if someone can help me. You should also note that currently the u value's are ints and I want to return this specific path as characters. The array size is 26 by 26 as there are 26 characters in the alphabet. A possible path could be C B A, or 2, 1, 0.
void dijkstra(int graph[MAX_ROWS][MAX_COLUMNS], int src){
int dist[MAX_ROWS]; // The output array. dist[i] will hold the shortest distance from src to i
bool sptSet[MAX_ROWS]; // sptSet[i] will true if vertex i is included in shortest path tree or shortest distance from src to i is finalized
int i, count, v;
struct path {
char thepath[40];
} pathArray[MAX_ROWS];
// Initialize all distances as INFINITE and stpSet[] as false
for (i = 0; i < MAX_ROWS; i++)
dist[i] = INT_MAX, sptSet[i] = false;
// Distance of source vertex from itself is always 0
dist[src] = 0;
// Find shortest path for all vertices
for (count = 0; count < MAX_ROWS-1; count++){
// Pick the minimum distance vertex from the set of vertices not
// yet processed. u is always equal to src in first iteration.
int u = minDistance(dist, sptSet);
int baby = u + 'A';
char girl = baby;
printf("Count : %d, u : %c\n", count, girl);
pathArray[v].thepath[v] = girl;
// Mark the picked vertex as processed
sptSet[u] = true;
// Update dist value of the adjacent vertices of the picked vertex.
for (v = 0; v < MAX_ROWS; v++)
// Update dist[v] only if is not in sptSet, there is an edge from
// u to v, and total weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u]+graph[u][v] < dist[v]){
dist[v] = dist[u] + graph[u][v];
}
}
// print the constructed distance array
printf("Vertex Distance from Source\n");
for (i = 0; i < MAX_ROWS; i++){
if (dist[i] != INT_MAX)
printf("%d \t\t %d Path: %s\n", i, dist[i], pathArray[i].thepath);
}
//printSolution(dist, MAX_ROWS, pathArray.thepath);
}
Your approach of pathArray has some problems:
First, you address the path via the vertex v, but v is uninitialised and it does not have any meaning outside the for loop.
Also, v isn't any meaningful information for the string: It is a vertex id. You also have the distance to the source, but the string index you need requires the number of steps to reach v from the source vertex, which you currently don't store.
Finally, you can only build your paths when all distances have been found, not during pathfinding.
A better approach is to keep an array prev[MAX_ROWS] that stores the vertex id of the vertex that lies directly before this vertex in the shortest path from the source to this vertex. That means you essentially store the path from the destination to the source. You can't do it the other way round, because the paths from the source may fork. Seen from the other end, that means that all paths eventually join when going towards the source, so storing the path as list of previous points is safe.
You set the previous vertex whenever you find a new shortest distance:
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u]+graph[u][v] < dist[v])
{
dist[v] = dist[u] + graph[u][v];
prev[v] = u;
}
You can then print the path from each vertex i to the source:
v = i;
while (v != src) {
putchar('A' + v);
v = prev[v];
}
putchar('A' + src);
putchar(10);
If you want to store the forward-going path, you can implement a recursive approach or write the path to a string and then reverse it.

Prim's Algorithm with Priority Queues implementation

void PrimMST(float A[GsizeSqr][GsizeSqr])
{
int i, j, pCount, gs, row, ind, findN;
gs = sqrt(GsizeSqr);
pCount = 0;
D_array MST; //MST contains the nodes of the MST and is initialized with the starting node
initArr(&MST, 1);
int p[GsizeSqr];
float priority[GsizeSqr]; //priority contains weight(u, p[u])
//Initialize p and priority with infinity and NULL values (note: -1 means null and 1000000 means inf)
for(i=0; i < GsizeSqr; i++){
p[i] = -1;
priority[i] = 1000000;
}
PriorityQueue Q; //Initialize priority queue that stores (priority, key) values
Q = init_heap(GsizeSqr);
for(i=0; i < gs; i++){ //Insert input adjacency matrix into priority queue
for(j=0; j < gs; j++){
node n;
n = create_node(A[i][j], pCount++);
enqueue(Q, n);
}
}
node start; //Select starting node and insert to MST
start = create_node(0, 0);
insArr(&MST, start);
priority[0] = 0;
while(Q->heap_size != 1){ //while Q not empty
node u;
u = dequeue(Q);
if(p[u.key] != -1)
insArr(&MST, u);
row = ceil(u.key/gs);
//For each adjacent node A[row][i]
for(i=0; i < gs; i++){
if(A[row][i] != 0.0){
ind = i*gs + row; //Calculate index of adjacent node
findN = find_node(Q, ind); //find and return index of adjacent node in queue
if(findN != 0 && u.priority < Q->elements[findN].priority){
set_priority(Q, findN, u.priority);
p[findN] = u.key;
}
}
}
}
}
I am trying to create a C implementation of Prim's Algorithm using priority queues using the pseudocode which is similar to many sources online. The end goal is (hopefully) some nifty maze generation. I'm just having confusion with the details of the implementation.
input: An adjacency matrix with random weights
desired output: The adjacency matrix for a minimal spanning tree
*EDIT: Added my (not working) attempt. I'm still getting an incorrect tree, I'm not sure where I'm going wrong. I think I would benefit from another set of eyes over this code.
first question:
A is the set that contains the edges of the MST.
p[u] means which node has the minimum edge with u currently, that is to say, if you have three edges(node 1, node 2, weight) (1,2,5), (1,3,4), (1,4,10), then p[1] = 3, and now priority[1] is 4.
second one:
nope, the node is pop after u := EXTRACT-MIN(Q);,

Resources