AO* algorithm is a search algorithm used in AI to find optimal solutions in AND‑OR graphs. It extends the A Star algorithm by handling more complex decision structures. In a regular OR graph (used by A Star), only one optimal path is selected.
- Evaluates multiple interconnected subproblems to construct an optimal solution.
- Uses heuristic information to guide the search efficiently.
- Commonly applied in planning, decision-making, and problem-solving tasks.

Need for AO* Algorithm
- Some problems require completing multiple subtasks before achieving a goal.
- Traditional search techniques struggle with hierarchical and decomposable problem structures.
- Complex planning and decision-making tasks often involve interdependent actions and outcomes.
- An approach is needed to efficiently evaluate and solve such structured problems.
Understanding AND–OR Graph
An AND–OR graph is a problem representation structure used when decisions involve both alternatives and mandatory combinations. Unlike simple trees, some nodes require selecting one option, while others require completing multiple tasks together.

1. OR Node
- An OR node represents a decision point where multiple alternatives are available, but only one option needs to be selected to move forward.
- The solution depends on choosing the most optimal or least costly branch among the available choices.
- Example: To reach a destination, you may choose: Route A or Route B. Selecting any one route is sufficient.
2. AND Node
- An AND node represents a situation where multiple sub-tasks must be completed together.
- The solution is valid only when all child nodes are solved.
- Example: To cook food, you must: Buy vegetables and Cook them. Both steps are necessary.
Heuristic and Cost Modelling in AO*
1. Heuristic Function
The heuristic function estimates the remaining cost from a node to the goal:
h(n) = estimated cost from noden to goal
It guides the algorithm toward promising paths and reduces unnecessary exploration.
2. Evaluation Function
Each node is assigned an evaluation value
f(n) = g(n) + h(n)
Where:
g(n) : actual cost from start node to noden h(n) : heuristic estimate from noden to goalf(n) : total estimated cost
3. Cost Calculation for OR Node
For an OR node, only one child is selected. The cost is the minimum among all children.
f(n) = \min_{i} \left( c(n, n_i) + f(n_i) \right)
Where:
c(n, n_i) : Cost from noden to child-
f(n_i) : Evaluation cost of child
4. Cost Calculation for AND Node
For an AND node, all children must be solved. The total cost is the sum of all child costs.
f(n) = \sum_{i} \left( c(n, n_i) + f(n_i) \right)
Where:
- All successors contribute to the final cost
- Every child must be included
5. Backpropagation Rule
After expanding a node, updated costs are propagated upward:
f(parent) \leftarrow \text{updated value based on children}
This continues until the root node is updated.
Working
- Initialization: Start with the initial (root) node and assign its heuristic value. This node represents the overall problem to be solved.
- Path Selection: Follow the currently most promising path based on heuristic cost values to identify nodes that are not yet expanded.
- Node Expansion: Select one of the unexpanded nodes and generate its successor nodes. Compute heuristic values for each successor.
- Solution Check: If a node has no successors or satisfies the goal condition, mark it as solved.
- Cost Backpropagation: Update the cost values of parent nodes based on the newly expanded successors. This adjustment moves from bottom to top.
- Best Path Update: Re evaluate the graph and choose the most promising path according to updated costs.
- Termination: Repeat the process until the start node is marked as solved or no better solution path exists.
Implementation of AO* in Python
Step 1: Define the Graph
Defines the AND, OR graph structure. It Contains:
- type: whether node is AND or OR
- children: list of (child, edge_cost)
graph = {
'A': {'type': 'OR', 'children': [('B', 1), ('C', 1)]},
'B': {'type': 'AND', 'children': [('D', 1), ('E', 1)]},
'C': {'type': 'OR', 'children': [('F', 1)]},
'D': {'type': 'OR', 'children': []},
'E': {'type': 'OR', 'children': []},
'F': {'type': 'OR', 'children': []}
}
Step 2: Define Heuristic values
Stores estimated remaining cost from each node to the goal. These values guide the search.
- Goal nodes (D, E, F) have heuristic 0
- Other nodes have estimated future cost
heuristic = {
'A': 1,
'B': 2,
'C': 1,
'D': 0,
'E': 0,
'F': 0
}
Step 3: Storage Structures
- cost: Stores computed cost of each node.
- solved: Marks whether a node is completely evaluated.
- solution_graph: Stores only the selected optimal branches.
cost = {}
solved = {}
solution_graph = {}
Step 4: Cost Computation
- if not graph[node]['children']: If the node has no children, it is a terminal (goal) node. Its cost is set to 0, marked as solved and recursion stops.
- if solved.get(node, False): If a node has already been solved, its stored cost is reused to avoid recomputation.
- if node_type == 'OR': For an OR node, the child with the minimum total cost is selected and added to the solution graph.
- elif node_type == 'AND': For an AND node, the function computes the cost of all children, adds their edge costs, and sums them. Since all subproblems must be solved, every child is included in the solution graph.
- After computing the cost, the node is marked as solved and its value is returned for backpropagation.
def ao_star(node):
if not graph[node]['children']:
cost[node] = 0
solved[node] = True
return 0
if solved.get(node, False):
return cost[node]
node_type = graph[node]['type']
if node_type == 'OR':
min_cost = float('inf')
best_child = None
for child, edge_cost in graph[node]['children']:
child_cost = edge_cost + ao_star(child)
if child_cost < min_cost:
min_cost = child_cost
best_child = child
cost[node] = min_cost
solution_graph[node] = [best_child]
elif node_type == 'AND':
total_cost = 0
children_list = []
for child, edge_cost in graph[node]['children']:
child_cost = edge_cost + ao_star(child)
total_cost += child_cost
children_list.append(child)
cost[node] = total_cost
solution_graph[node] = children_list
solved[node] = True
return cost[node]
Step 5: Extracting Optimal Solution Graph
After computing costs, the function reconstructs the optimal solution graph. It selects the minimum-cost child for OR nodes and includes all children for AND nodes, producing the final optimal solution structure.
def extract_solution(node, solution_graph):
if not graph[node]['children']:
return
node_type = graph[node]['type']
if node_type == 'OR':
min_cost = float('inf')
best_child = None
for child, edge_cost in graph[node]['children']:
child_cost = edge_cost + cost[child]
if child_cost < min_cost:
min_cost = child_cost
best_child = child
solution_graph[node] = [best_child]
extract_solution(best_child, solution_graph)
elif node_type == 'AND':
children_list = []
for child, edge_cost in graph[node]['children']:
children_list.append(child)
extract_solution(child, solution_graph)
solution_graph[node] = children_list
Step 6: Run the Algorithm
The algorithm starts from the root node A, computes the minimum total cost and then extracts the final optimal solution graph.
result = ao_star('A')
extract_solution('A', solution_graph)
print("Minimum cost:", result)
print("Solution Graph:", solution_graph)
Output:

Step 7: Visualizing Graph
Here, we visualize comparison of the AND OR graph before applying AO Star and the optimized solution graph after the algorithm selects the minimum cost branches.
1. AND OR Graph Before Applying AO Star*
This diagram shows the complete problem before applying AO Star, where all possible branches are still present and no optimal choice has been made. A is an OR node that can choose between B and C, B is an AND node that requires both D and E to be solved and C is an OR node that leads to F, while D, E and F are goal nodes.
- A can choose B or C
- B requires solving both D and E
- C requires solving F
import networkx as nx
import matplotlib.pyplot as plt
def draw_full_graph_with_types(graph):
G = nx.DiGraph()
for node in graph:
G.add_node(node)
for child, cost in graph[node]['children']:
G.add_edge(node, child, weight=cost)
pos = nx.spring_layout(G)
or_nodes = [n for n in graph if graph[n]['type'] == 'OR']
and_nodes = [n for n in graph if graph[n]['type'] == 'AND']
nx.draw_networkx_nodes(G, pos,
nodelist=or_nodes,
node_color='lightblue',
node_shape='o',
node_size=2000)
nx.draw_networkx_nodes(G, pos,
nodelist=and_nodes,
node_color='orange',
node_shape='s',
node_size=2000)
nx.draw_networkx_edges(G, pos)
nx.draw_networkx_labels(G, pos)
labels = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels=labels)
plt.title("AND-OR Graph (OR = Circle, AND = Square)")
plt.show()
draw_full_graph_with_types(graph)
Output:

2. Solution Graph After Applying AO Star
This diagram shows the optimized structure after applying AO Star, where the algorithm has compared costs and removed the higher cost branch. Since B is an AND node, it requires solving both D and E, making its total cost higher, while C only requires solving F, resulting in a lower cost.
- A selects C
- C selects F
- The branch through B is removed
def draw_solution_graph(solution_graph, start_node):
G = nx.DiGraph()
visited = set()
def build_graph(node):
if node in visited:
return
visited.add(node)
if node in solution_graph:
for child in solution_graph[node]:
G.add_edge(node, child)
build_graph(child)
build_graph(start_node)
pos = nx.spring_layout(G)
nx.draw(G, pos,
with_labels=True,
node_size=2000,
node_color="lightgreen",
arrows=True)
plt.title("Solution Graph (After AO*)")
plt.show()
draw_solution_graph(solution_graph, 'A')
Output:

You can download the full code from here.
Applications
- Automated Planning Systems: Used to generate optimal plans that involve multiple dependent tasks.
- Expert Systems: Helps solve complex decision-making problems with alternative and mandatory choices.
- Problem Decomposition: Breaks large problems into smaller interconnected subproblems and solves them efficiently.
- Game Playing and Strategy Planning: Evaluates different decision paths to identify the most promising strategy.
- Robotics: Assists robots in planning sequences of actions that require completing multiple subtasks.
Advantages
- Efficient for complex AND OR problems
- Avoids exploring unnecessary branches
- Suitable for problem reduction approaches
- Handles dependent sub tasks effectively
- Produces an optimal solution graph
Limitations
- Requires a good heuristic for better performance
- Implementation is more complex than A Star
- Can consume high memory for large graphs
- Performance may degrade in very large state spaces
Related Article: