How to implement A* with minimum number of nodes on path? - algorithm

I have implemented my A* algorithm such that it finds the shortest path to goal, given that it can move only to neighboring/adjacent cells. (Assume nodes are cells in a grid). So there's 8 surrounding cells it can move.
OOO
O*O
OOO
This works and finds the shortest path but what if I only want the nodes that are about 20-40 cells apart, and less if needed (say a door is only one cell away. How would I go about this without post processing the path?
So something like this?
XXXXOXOXOXXXX
XXXXXOOOXXXXX
OOOOOO*OOOOOO
XXXXXOOOXXXXX
XXXXOXOXOXXXX
Where O are the 'neighbors and X's are not.
def search(grid,start,goal):
dist = {}
visited = {}
predecessors= {}
hscore = {}
gscore = {}
gscore[start] = 0
hscore[start] = gscore[start] + heuristic(start,goal)
pq = PriorityQueue()
pq.put((hscore[start],start))
while not pq.empty():
current = pq.get()
if current[1] == goal:
return build_path(predecessors,goal)
visited[current[1]] = current[1]
max_dist = 0
succs = successors(grid,current[1],goal,pixels=90)
for successor in succs:
if visited.get(successor[0],None) != None:
continue
grid.grid[successor[0]] = (0,255,0)
g = gscore[current[1]] + 1
in_pq = successor[0] in pq
if (not in_pq or g < gscore[successor[0]] ):
predecessors[successor[0]] = current[1]
gscore[successor[0]] = g
hscore[successor[0]] = g + heuristic(successor[0],goal)
max_dist = dist
if not in_pq:
pq.put((hscore[successor[0]],successor[0]))
return []

Related

Is there a way to find a path in a tree?

Let's say we have a tree like the one below. Is there an algorithm that given 2 nodes find the path that connects them. For example, given (A,E) it will return [A,B,E], or given (D,G) it will return [D,B,A,C,G]
A
/ \
B C
/ \ / \
D E F G
You will need to have a tree implementation where a child node has a link to its parent.
Then for both nodes you can build the path from the node to the root, just by following the parent link.
Then compare the two paths, starting from the ends of the paths (where the root is): as long as they are the same, remove that common node from both paths.
Finally you are left with two diverting paths. Reverse the second, and join the two paths, putting the last removed node in between the two.
Here is an implementation in JavaScript:
function getPathToRoot(a) {
if (a.parent == null) return [a];
return [a].concat(getPathToRoot(a.parent));
}
function findPath(a, b) {
let p = getPathToRoot(a);
let q = getPathToRoot(b);
let common = null;
while (p.length > 0 && q.length > 0 && p[p.length-1] == q[q.length-1]) {
common = p.pop();
q.pop();
}
return p.concat(common, q.reverse());
}
// Create the example tree
let nodes = {};
for (let label of "ABCDEFG") {
nodes[label] = { label: label, parent: null };
}
nodes.B.parent = nodes.C.parent = nodes.A;
nodes.D.parent = nodes.E.parent = nodes.B;
nodes.F.parent = nodes.G.parent = nodes.C;
// Perform the algorithm
let path = findPath(nodes.E, nodes.G);
// Output the result
console.log("Path from E to G is:");
for (let node of path) {
console.log(node.label);
}

Tree from balanced parenthesis

I have to find height of tree and find protection number (or just to generate a tree) from balanced parentheses.
For example:
()()()() creates tree like a list with height 3.
I have no idea how to convert parentheses to tree. I found some 'answers':
http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf (second page contains all examples for tree with 4 nodes)
paragraph - Binary Trees, Forests, Non-Crossing Pairs :
https://sahandsaba.com/interview-question-generating-all-balanced-parentheses.html
However, I still don't know how to create a tree from such defined parentheses. I have some impression that in Knuth, authors treat it as something obvious.
Do I miss something or it's not that simple?
Is it necessary to create a forest and then a binary tree?
A pair of parentheses represents a node. What appears within those parentheses represents its left child's subtree (according to the same rules). What appears at the right of those parentheses represents the node's right child's subtree (again, according to the same rules).
The conversion of this encoding into a binary tree can be done recursively like this:
function makeBinaryTree(input):
i = 0 # character index in input
function recur():
if i >= input.length or input[i] == ")":
i = i + 1
return NIL
i = i + 1
node = new Node
node.left = recur()
if i >= input.length or input[i] == ")":
i = i + 1
return node
node.right = recur()
return node
return recur()
Here is an implementation in JavaScript that performs the conversion for each of those 4-noded trees, and pretty prints the resulting trees:
function makeBinaryTree(input) {
let i = 0; // character index in input
return recur();
function recur() {
if (i >= input.length || input[i++] === ")") return null;
let node = { left: recur(), right: null };
if (i >= input.length || input[i] === ")") {
i++;
return node;
}
node.right = recur();
return node;
}
}
// Helper function to pretty print a tree
const disc = "\u2B24";
function treeAsLines(node) {
let left = [""], right = [""];
if (node.left) left = treeAsLines(node.left);
if (node.right) right = treeAsLines(node.right);
while (left.length < right.length) left.push(" ".repeat(left[0].length));
while (left.length > right.length) right.push(" ".repeat(left[0].length));
let topLeft = "", topRight = "";
let i = left[0].indexOf(disc);
if (i > -1) topLeft = "┌".padEnd(left[0].length-i+1, "─");
i = right[0].indexOf(disc);
if (i > -1) topRight = "┐".padStart(i+2, "─");
return [topLeft.padStart(left[0].length+1) + disc + topRight.padEnd(right[0].length+1)]
.concat(left.map((line, i) => line + " " + right[i]));
}
// The trees as listed in Table 1 of http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf
let inputs = [
"()()()()",
"()()(())",
"()(())()",
"()(()())",
"()((()))",
"(())()()",
"(())(())",
"(()())()",
"(()()())",
"(()(()))",
"((()))()",
"((())())",
"((()()))",
"(((())))"
];
for (let input of inputs) {
let tree = makeBinaryTree(input);
console.log(input);
console.log(treeAsLines(tree).join("\n"));
}
If I understood Knuth correctly, the representation works as the following: A pair of matching parentheses represents a node, e.g. () = A. Two consecutive pairs of matching parentheses means that the second node is the right child of the first one, e.g. ()() = A -> B. And two pairs of embedded parentheses means the inside node is the left child of the outside node, i.e. (()) = B <- A. Therefore, ()()()() = A -> B -> C -> D.
A possible algorithm to convert parentheses to binary tree would be:
convert(parentheses):
if parentheses is empty:
return Nil
root = Node()
left_start = 1
left_end = Nil
open = 0
for p = 0 to |parentheses|-1:
if parentheses[p] == '(':
open += 1
else
open -= 1
if open == 0:
left_end = p
break
root.left = convert(parentheses[left_start:left_end] or empty if index out of bound)
root.right = convert(parentheses[left_end+1:] or empty if index out of bound)
return root
It works by converting parentheses (L)R in the binary tree L <- A -> R recursively.

How do I optimize my Dijkstra algorithm in Matlab to decrease the running time?

Given below is my Dijkstra algorithm. The B matrix is the cost map. The source node is R=[1,1] and there is no target node. I want to just compute the Dijkstra algorithm given the source node to all the nodes in matrix.
But my Dijkstra takes more than 20 minutes to run. I am not sure how to optimize my code. Can you please help me out here?
function hMap = djikstra(B,R)
%B = Cost Map
%R = Initial position of the robot
fprintf('In Dijkstra');
hMap = Inf(length(B)); % Assigning infinity
hMap(R(1),R(2)) = 0 ; % source node
open = [];
open = [R(1),R(2),0];
closed = [];
closed = [closed; open(1,1:2)]; %Put current source node in closed
x = R(1);
y = R(2);
while(size(open) ~= 0)
if(x-1 ~=0)
if(sum(ismember(closed(:,1:2),[x-1,y],'rows'))== 0)
cost = hMap(x,y)+ B(x-1,y);
fprintf('x-1');
%if(cost < hMap(x-1,y) )
hMap(x-1,y) = min(cost,hMap(x-1,y));
fprintf(' update x-1');
open = [open;x-1,y,hMap(x-1,y)];
%end
end
end
if(x+1 <= length(B))
if(sum(ismember(closed(:,1:2),[x+1,y],'rows'))== 0)
cost = hMap(x,y)+ B(x+1,y) ;
%if( cost < hMap(x+1,y))
hMap(x+1,y) = min(cost,hMap(x+1,y));
open = [open;x+1,y,hMap(x+1,y)];
%end
end
end
if(y-1 ~= 0)
if(sum(ismember(closed(:,1:2),[x,y-1],'rows'))== 0)
cost = hMap(x,y)+ B(x,y-1);
%if( cost < hMap(x,y-1))
hMap(x,y-1) = min(cost, hMap(x,y-1));
open = [open;x,y-1,hMap(x,y-1)] ;
%end
end
end
if(y+1 <= length(B))
if(sum(ismember(closed(:,1:2),[x,y+1],'rows'))== 0)
cost = hMap(x,y)+ B(x,y+1);
%if(cost< hMap(x,y+1))
hMap(x,y+1) = min(cost,hMap(x,y+1));
open = [open;x,y+1,hMap(x,y+1)];
%end
end
end
closed = [closed;x,y];
open = open(2:size(open,1),:); %Removing source element from the open list
open = unique(open,'rows');
open = sortrows(open,3); % Sorting w.r.t G Value
fprintf('------------------------------OPEN--------------------------')
open
if(size(open) ~= 0)
x = open(1,1)
y = open(1,2)
end
end
end

MATLAB program takes more than 1 hour to execute

The below program is a program for finding k-clique communities from a input graph.
The graph dataset can be found here.
The first line of the dataset contains 'number of nodes and edges' respectively. The following lines have 'node1 node2' representing an edge between node1 and node2 .
For example:
2500 6589 // number_of_nodes, number_of_edges
0 5 // edge between node[0] and node[5]
.
.
.
The k-clique( aCliqueSIZE, anAdjacencyMATRIX ) function is contained here.
The following commands are executed in command window of MATLAB:
x = textread( 'amazon.graph.small' ); %% source input file text
s = max(x(1,1), x(1,2)); %% take largest dimemsion
adjMatrix = sparse(x(2:end,1)+1, x(2:end,2)+1, 1, s, s); %% now matrix is square
adjMatrix = adjMatrix | adjMatrix.'; %% apply "or" with transpose to make symmetric
adjMatrix = full(adjMatrix); %% convert to full if needed
k=4;
[X,Y,Z]=k_clique(k,adjMatrix); %%
% The output can be viewed by the following commands
celldisp(X);
celldisp(Y);
Z
The above program takes more than 1 hour to execute whereas I think this shouldn't be the case. While running the program on windows, I checked the task manager and found that only 500 MB is allocated for the program. Is this the reason for the slowness of the program? If yes, then how can I allocate more heap memory (close to 4GB) to this program in MATLAB?
The problem does not seem to be Memory-bound
Having a sparse, square, symmetric matrix of 6k5 * 6k5 edges does not mean a big memory.
The provided code has many for loops and is heavily recursive in the tail function transfer_nodes()
Add a "Stone-Age-Profiler" into the code
To show the respective times spent on a CPU-bound sections of the processing, wrap the main sections of the code into a construct of:
tic(); for .... end;toc()
which will print you the CPU-bound times spent on relevent sections of the k_clique.m code, showing the readings "on-the-fly"
Your original code k_clique.m
function [components,cliques,CC] = k_clique(k,M)
% k-clique algorithm for detecting overlapping communities in a network
% as defined in the paper "Uncovering the overlapping
% community structure of complex networks in nature and society"
%
% [X,Y,Z] = k_clique(k,A)
%
% Inputs:
% k - clique size
% A - adjacency matrix
%
% Outputs:
% X - detected communities
% Y - all cliques (i.e. complete subgraphs that are not parts of larger
% complete subgraphs)
% Z - k-clique matrix
nb_nodes = size(M,1); % number of nodes
% Find the largest possible clique size via the degree sequence:
% Let {d1,d2,...,dk} be the degree sequence of a graph. The largest
% possible clique size of the graph is the maximum value k such that
% dk >= k-1
degree_sequence = sort(sum(M,2) - 1,'descend');
%max_s = degree_sequence(1);
max_s = 0;
for i = 1:length(degree_sequence)
if degree_sequence(i) >= i - 1
max_s = i;
else
break;
end
end
cliques = cell(0);
% Find all s-size kliques in the graph
for s = max_s:-1:3
M_aux = M;
% Looping over nodes
for n = 1:nb_nodes
A = n; % Set of nodes all linked to each other
B = setdiff(find(M_aux(n,:)==1),n); % Set of nodes that are linked to each node in A, but not necessarily to the nodes in B
C = transfer_nodes(A,B,s,M_aux); % Enlarging A by transferring nodes from B
if ~isempty(C)
for i = size(C,1)
cliques = [cliques;{C(i,:)}];
end
end
M_aux(n,:) = 0; % Remove the processed node
M_aux(:,n) = 0;
end
end
% Generating the clique-clique overlap matrix
CC = zeros(length(cliques));
for c1 = 1:length(cliques)
for c2 = c1:length(cliques)
if c1==c2
CC(c1,c2) = numel(cliques{c1});
else
CC(c1,c2) = numel(intersect(cliques{c1},cliques{c2}));
CC(c2,c1) = CC(c1,c2);
end
end
end
% Extracting the k-clique matrix from the clique-clique overlap matrix
% Off-diagonal elements <= k-1 --> 0
% Diagonal elements <= k --> 0
CC(eye(size(CC))==1) = CC(eye(size(CC))==1) - k;
CC(eye(size(CC))~=1) = CC(eye(size(CC))~=1) - k + 1;
CC(CC >= 0) = 1;
CC(CC < 0) = 0;
% Extracting components (or k-clique communities) from the k-clique matrix
components = [];
for i = 1:length(cliques)
linked_cliques = find(CC(i,:)==1);
new_component = [];
for j = 1:length(linked_cliques)
new_component = union(new_component,cliques{linked_cliques(j)});
end
found = false;
if ~isempty(new_component)
for j = 1:length(components)
if all(ismember(new_component,components{j}))
found = true;
end
end
if ~found
components = [components; {new_component}];
end
end
end
function R = transfer_nodes(S1,S2,clique_size,C)
% Recursive function to transfer nodes from set B to set A (as
% defined above)
% Check if the union of S1 and S2 or S1 is inside an already found larger
% clique
found_s12 = false;
found_s1 = false;
for c = 1:length(cliques)
for cc = 1:size(cliques{c},1)
if all(ismember(S1,cliques{c}(cc,:)))
found_s1 = true;
end
if all(ismember(union(S1,S2),cliques{c}(cc,:)))
found_s12 = true;
break;
end
end
end
if found_s12 || (length(S1) ~= clique_size && isempty(S2))
% If the union of the sets A and B can be included in an
% already found (larger) clique, the recursion is stepped back
% to check other possibilities
R = [];
elseif length(S1) == clique_size;
% The size of A reaches s, a new clique is found
if found_s1
R = [];
else
R = S1;
end
else
% Check the remaining possible combinations of the neighbors
% indices
if isempty(find(S2>=max(S1),1))
R = [];
else
R = [];
for w = find(S2>=max(S1),1):length(S2)
S2_aux = S2;
S1_aux = S1;
S1_aux = [S1_aux S2_aux(w)];
S2_aux = setdiff(S2_aux(C(S2(w),S2_aux)==1),S2_aux(w));
R = [R;transfer_nodes(S1_aux,S2_aux,clique_size,C)];
end
end
end
end
end

Coloring specific type of the planar graph

I've got a specific type of the planar graph and I found it interesting to search for an algorithm which will color its vertices legally. About this type of graph, it's very easy and cool:
Consider any tree T with n>2 vertices and k leaves. Let's denote G(T) as a graph constructed from T by connecting its leaves into k-cycle in such way that G(T) is planar.
And the problem I came up with is to color G(T) with 3 colors. Clearly, G(T) as a planar graph, is 4-colorable, but I think (don't have a proof) that it is almost always 3-colorable due to its simplicity. Almost always means that only if T is a star and only with odd number of leaves, then G(T) is 4-colorable.
I am looking for some algorithm, or maybe proof of my assumptions which could be easily transformed into an algorithm. I would be very very grateful for any help, hints.
In case I wasn't clear enough I'll give an example:
Let T be a tree with edges E(T) = { {1,2}, {2,3}, {2,4}, {4,5} } and then E(G(T)) = sum of the sets: E(T) and { {1,5}, {5,3}, {3,1} }, since we are connecting leaves 1,5,3 into a cycle.
local Edges_of_Tree = {{1,2}, {2,3}, {2,4}, {4,5}}
local Cycle_of_Leaves = {1,5,3}
local color1 = 'Red'
local color2 = 'Green'
local color3 = 'Blue'
local vert = {}
local vert_arr = {}
local function add_edge(v1, v2)
assert(v1 ~= v2)
if not vert[v1] then
vert[v1] = {deg = 0, adj = {}}
table.insert(vert_arr, v1)
end
vert[v1].deg = vert[v1].deg + 1
assert(not vert[v1].adj[v2], 'multiple edges between '..v1..' and '..v2)
vert[v1].adj[v2] = true
end
for _, edge in ipairs(Edges_of_Tree) do
local v1, v2 = unpack(edge)
add_edge(v1, v2)
add_edge(v2, v1)
end
table.sort(vert_arr)
local leaf_ctr = 0
local root
for v, vv in pairs(vert) do
if vv.deg == 1 then
leaf_ctr = leaf_ctr + 1
else
root = v
end
end
assert(#vert_arr > leaf_ctr + 1, 'tree is a star')
assert(leaf_ctr == #Cycle_of_Leaves, 'invalid Cycle_of_Leaves')
for _, v in ipairs(Cycle_of_Leaves) do
assert(vert[v] and vert[v].deg == 1 and vert[v].color == nil,
'invalid Cycle_of_Leaves')
vert[v].color = false
end
local function recursive_paint_inodes(v, color, prev_v)
assert(vert[v].color == nil, 'a cycle in tree found')
vert[v].color = color
local next_color = (color1..color2):gsub(color, '')
for next_v in pairs(vert[v].adj) do
if next_v ~= prev_v and vert[next_v].deg > 1 then
recursive_paint_inodes(next_v, next_color, v)
end
end
end
recursive_paint_inodes(root, color1)
local front
for i = 1, leaf_ctr do
local vv = vert[Cycle_of_Leaves[i]]
vv.next = Cycle_of_Leaves[i % leaf_ctr + 1]
vv.prev = Cycle_of_Leaves[(i - 2) % leaf_ctr + 1]
local parent = next(vv.adj)
if parent ~= next(vert[vv.prev].adj) then
assert(not vert[parent].conn_to_leaf, 'graph is non-planar')
vert[parent].conn_to_leaf = true
front = Cycle_of_Leaves[i]
end
end
vert[next(vert[vert[front].prev].adj)].color = color3
vert[front].color = color3
local tricolor = color1..color2..color3
local leaf = front
for i = 1, leaf_ctr - 1 do
local prev_color = vert[leaf].color
leaf = vert[leaf].next
local parent_color = vert[next(vert[leaf].adj)].color
local enabled_colors = tricolor:gsub(prev_color, ''):gsub(parent_color, '')
vert[leaf].color = enabled_colors:match(color1)
or enabled_colors:match(color2) or color3
end
for _, v in ipairs(vert_arr) do
print(v..' '..vert[v].color)
end
This code is written in Lua.
You can test it in action there.

Resources