Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added Astar Search Algorithm in Graphs #1739

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions Graphs/Astar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Author: Mathang Peddi
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use JSDoc annotations like @author.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have changed it to @author: Mathang Peddi
Do I need to make any other change here?

* A* Search Algorithm implementation in JavaScript
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* A* Search Algorithm implementation in JavaScript

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this line.

* A* Algorithm calculates the minimum cost path between two nodes.
* It is used to find the shortest path using heuristics.
* It uses graph data structure.
*/

function createGraph(V, E) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is unnecessary. Just take the graph in adjacency list representation. There is also no need to restrict this to undirected graphs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this function, created an adjacency list and directly passed it to the function.

// V - Number of vertices in graph
// E - Number of edges in graph (u,v,w)
const adjList = [] // Adjacency list
for (let i = 0; i < V; i++) {
adjList.push([])
}
for (let i = 0; i < E.length; i++) {
adjList[E[i][0]].push([E[i][1], E[i][2]])
adjList[E[i][1]].push([E[i][0], E[i][2]])
}
return adjList
}

// Heuristic function to estimate the cost to reach the goal
// You can modify this based on your specific problem, for now, we're using Manhattan distance
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a useful manhattan distance. This is just the absolute distance between vertex IDs. Instead you want some kind of associated "points" (say, in 2d or 3d space) for which you compute distances.

In any case, the heuristic function should probably be a (mandatory) parameter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made the changes, I am using Euclidian Distance here, do I need to make any other change here?

function heuristic(a, b) {
return Math.abs(a - b)
}

function aStar(graph, V, src, target) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, just take the graph in adjacency list representation. V is then redundant (and also conflicts with our naming scheme).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it.

const openSet = new Set([src]) // Nodes to explore
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a priority queue by fScore otherwise time complexity is messed up.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have changed the logic, have used the priority queue implementation - have coded it using the normal approach(without using inbuilt PQ package), is this fine or do I need to make any other changes here?

const cameFrom = Array(V).fill(-1) // Keep track of path
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use null instead of -1, it's the idiomatic value to use in JS for absence of a value.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

const gScore = Array(V).fill(Infinity) // Actual cost from start to a node
gScore[src] = 0

const fScore = Array(V).fill(Infinity) // Estimated cost from start to goal (g + h)
fScore[src] = heuristic(src, target)

while (openSet.size > 0) {
// Get the node in openSet with the lowest fScore
let current = -1
openSet.forEach((node) => {
if (current === -1 || fScore[node] < fScore[current]) {
current = node
}
})

// If the current node is the target, reconstruct the path and return
if (current === target) {
const path = []
while (cameFrom[current] !== -1) {
path.push(current)
current = cameFrom[current]
}
path.push(src)
return path.reverse()
}

openSet.delete(current)

// Explore neighbors
for (let i = 0; i < graph[current].length; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just do for (const [neighbor, weight] of graph[current])

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

const neighbor = graph[current][i][0]
const tentative_gScore = gScore[current] + graph[current][i][1]

if (tentative_gScore < gScore[neighbor]) {
cameFrom[neighbor] = current
gScore[neighbor] = tentative_gScore
fScore[neighbor] = gScore[neighbor] + heuristic(neighbor, target)

if (!openSet.has(neighbor)) {
openSet.add(neighbor)
}
}
}
}

return [] // Return empty path if there's no path to the target
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be null instead.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

}

module.exports = { createGraph, aStar }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
module.exports = { createGraph, aStar }
export { aStar }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.


// const V = 9
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be a test instead.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this part, do you want me to add a Astar.test.js file as a part of Unit Testing?

// const E = [
// [0, 1, 4],
// [0, 7, 8],
// [1, 7, 11],
// [1, 2, 8],
// [7, 8, 7],
// [6, 7, 1],
// [2, 8, 2],
// [6, 8, 6],
// [5, 6, 2],
// [2, 5, 4],
// [2, 3, 7],
// [3, 5, 14],
// [3, 4, 9],
// [4, 5, 10]
// ]

// const graph = createGraph(V, E)
// const path = aStar(graph, V, 0, 4) // Find path from node 0 to node 4
// console.log(path)

/**
* The function returns the optimal path from the source to the target node.
* The heuristic used is Manhattan distance but it can be modified.
*/