{"slug": "peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-cost", "title": "PeopleSoft to AI | Part 16: Uniform-Cost Search — What If Every Action Has a Different Cost?", "summary": "Uniform-Cost Search (UCS) is introduced as a graph traversal algorithm that finds the cheapest path by considering accumulated path cost, unlike DFS or BFS. In a weighted graph example with edge costs from START to TREASURE, UCS correctly identifies the route START → A → D → G → TREASURE with total cost 6 as the cheapest among four possible routes. The article, part of the 'PeopleSoft to AI' series, explains that UCS uses a priority queue and tracks g(n), the cumulative cost from the start node, to expand the lowest-cost path first.", "body_md": "In the [ previous article](https://medium.com/@gokulkalauni03/peoplesoft-to-ai-part-15a-depth-first-search-dfs-explained-simply-d092a8ad85ac?sharedUserId=gokulkalauni03), we looked at\n\nDFS is useful when we want to find a path through a search space. But what if finding *any* path isn’t enough?\n\nWhat if every action has a different cost?\n\nMaybe one action takes one second while another takes ten. Maybe one route uses fewer resources, while another requires more computation.\n\nIn that situation, the shortest path isn’t necessarily the best path.\n\nWe need a search algorithm that considers **cost**.\n\nThat is where **Uniform-Cost Search (UCS)** comes in.\n\n**A Small Change in Perspective**\n\nUp to this point, we’ve used PeopleSoft examples to make the concepts familiar.\n\nFrom here, we’ll sometimes use simpler, generic examples when they explain the algorithm more clearly.\n\nThe goal isn’t to force every algorithm into a PeopleSoft scenario.\n\nIt’s to understand the algorithm well enough to recognize where it can eventually be useful in enterprise systems and AI.\n\nFor UCS, a weighted graph gives us a much better way to understand the idea.\n\n**The Problem**\n\nImagine we have a graph where every connection has a different cost.\n\nOur goal is simple:\n\nFind the cheapest path from START to TREASURE.\n\nHere’s the graph we’ll use throughout this article:\n\nThe graph contains several possible routes to TREASURE.\n\nThe edge costs are:\n\n```\nSTART → A         Cost 2START → B         Cost 1A → C             Cost 2A → D             Cost 1B → E             Cost 4B → F             Cost 1C → G             Cost 3D → G             Cost 1D → H             Cost 2E → H             Cost 1F → I             Cost 2G → TREASURE      Cost 2H → TREASURE      Cost 1I → TREASURE      Cost 4\n```\n\nThere are multiple ways to reach the same destination.\n\nFor example:\n\n```\nRoute ASTART → A → C → G → TREASURECost = 2 + 2 + 3 + 2     = 9\n```\n\nAnother route is:\n\n```\nRoute BSTART → A → D → G → TREASURECost = 2 + 1 + 1 + 2     = 6\n```\n\nWe also have:\n\n```\nRoute CSTART → B → E → H → TREASURECost = 1 + 4 + 1 + 1     = 7\n```\n\nAnd:\n\n```\nRoute DSTART → B → F → I → TREASURECost = 1 + 1 + 2 + 4     = 8\n```\n\nAll four routes reach the same destination.\n\nBut they don’t have the same total cost.\n\nThe cheapest route is:\n\n```\nSTART → A → D → G → TREASURETotal Cost = 6\n```\n\nThe question is:\n\nHow can an algorithm discover that route without simply trying every complete route first?\n\nThat’s where Uniform-Cost Search comes in.\n\n**From Depth to Cost**\n\nDFS primarily cares about going deeper.\n\nBFS primarily cares about the number of steps.\n\nUCS cares about the **total cost accumulated so far**.\n\nThat’s the fundamental difference.\n\nImagine we start at START.\n\nThere are two immediate choices:\n\n```\nSTART → A        Cost = 2START → B        Cost = 1\n```\n\nA normal FIFO queue would process nodes according to discovery order.\n\nUCS doesn’t.\n\nIt places both paths into a priority queue and chooses the one with the lowest accumulated cost:\n\n```\nPriority QueueSTART → B        Cost = 1START → A        Cost = 2\n```\n\nSo B is expanded first.\n\nThis is important because a node that is discovered later can still be explored before a node that was discovered earlier if its path is cheaper.\n\nThat’s the fundamental idea behind UCS.\n\n**Cumulative Cost**\n\nThe important detail is that UCS doesn’t look only at the cost of the next edge.\n\nIt tracks the total cost from START to the current node.\n\nWe usually represent this as:\n\n```\ng(n)\n```\n\nwhere g(n) means:\n\nThe cost of the path from the starting node to node n.\n\nFor example:\n\n```\nSTART  |  | 1  ↓  B  |  | 1  ↓  F  |  | 2  ↓  I\n```\n\nTherefore:\n\n```\ng(B) = 1g(F) = 1 + 1     = 2g(I) = 1 + 1 + 2     = 4\n```\n\nThe edge leading to I costs 2.\n\nBut the cost of the path reaching I is 4.\n\nThat distinction is critical.\n\nUCS works with **accumulated path cost**, not isolated edge cost.\n\n**How UCS Actually Works**\n\nLet’s walk through the exact graph step by step.\n\nInitially:\n\n```\nPriority QueueSTARTCost = 0\n```\n\nWe pop START.\n\nIt has two possible next states:\n\n```\nSTART → A        Cost = 2START → B        Cost = 1\n```\n\nSo the priority queue becomes:\n\n```\nPriority QueueSTART → B        Cost = 1START → A        Cost = 2\n```\n\nUCS chooses START → B because its accumulated cost is lower.\n\nFrom B, there are two possible next states:\n\n```\nSTART → B → E        Cost = 1 + 4 = 5START → B → F        Cost = 1 + 1 = 2\n```\n\nThe queue now contains:\n\n```\nPriority QueueSTART → A           Cost = 2START → B → F       Cost = 2START → B → E       Cost = 5\n```\n\nThere is now a tie at cost 2.\n\nThe important thing is that UCS only cares about the **priority value** here: the accumulated cost.\n\nOur implementation can use a secondary ordering to decide which equal-cost entry is processed first.\n\nIn the execution shown in the companion video, A is processed before F.\n\nFrom A, we can reach C and D:\n\n```\nSTART → A → C        Cost = 2 + 2 = 4START → A → D        Cost = 2 + 1 = 3\n```\n\nThe queue now contains:\n\n```\nPriority QueueSTART → B → F       Cost = 2START → A → D       Cost = 3START → A → C       Cost = 4START → B → E       Cost = 5\n```\n\nUCS chooses START → B → F next because 2 is the lowest cost.\n\nFrom F, we reach I:\n\n```\nSTART → B → F → ICost = 1 + 1 + 2     = 4\n```\n\nThe queue now contains:\n\n```\nPriority QueueSTART → A → D       Cost = 3START → A → C       Cost = 4START → B → F → I   Cost = 4START → B → E       Cost = 5\n```\n\nUCS chooses START → A → D because its accumulated cost is 3.\n\nFrom D, there are two possible next states:\n\n```\nSTART → A → D → GCost = 2 + 1 + 1     = 4\n```\n\nand:\n\n```\nSTART → A → D → HCost = 2 + 1 + 2     = 5\n```\n\nThe queue now contains several candidates:\n\n```\nPriority QueueSTART → A → C       Cost = 4START → B → F → I   Cost = 4START → A → D → G   Cost = 4START → B → E       Cost = 5START → A → D → H   Cost = 5\n```\n\nNotice what UCS is doing.\n\nIt isn’t following one complete route from beginning to end.\n\nIt is continuously comparing the **cheapest available partial paths**.\n\nThat is what makes UCS different from DFS.\n\nNow suppose the path through C is expanded:\n\n```\nSTART → A → C → GCost = 2 + 2 + 3     = 7\n```\n\nBut we already have a cheaper way to reach G:\n\n```\nSTART → A → D → GCost = 4\n```\n\nSo the path through C isn’t competitive.\n\nThis is another important property of UCS: reaching the same node through different paths doesn’t automatically mean all paths are equally useful.\n\nThe accumulated cost matters.\n\nEventually, UCS expands:\n\n```\nSTART → A → D → G\n```\n\nwith:\n\n```\nCost = 4\n```\n\nFrom G, we can finally reach TREASURE:\n\n```\nSTART → A → D → G → TREASURECost = 2 + 1 + 1 + 2     = 6\n```\n\nThe priority queue may still contain other paths.\n\nFor example:\n\n```\nSTART → B → ECost = 5START → A → D → HCost = 5START → B → F → ICost = 4\n```\n\nBut the newly generated path to TREASURE has cost 6.\n\nOnce TREASURE is popped from the priority queue, UCS can stop because, with non-negative edge costs, no later path can have a lower total cost.\n\nThe final answer is:\n\n```\nSTART → A → D → G → TREASURETotal Cost = 6\n```\n\nThis is exactly the behaviour shown in the companion video.\n\nThe important idea is:\n\n**UCS always expands the currently cheapest path, not simply the next path discovered.**\n\n**Watch UCS in Action**\n\nThe graph is much easier to understand when you can actually watch the priority queue change after every step.\n\nThe companion video for this article walks through the same graph and shows UCS selecting nodes based on their accumulated cost until it reaches TREASURE.\n\nAs you watch it, pay attention to three things:\n\n```\n1. Which node is selected next?2. What is its accumulated cost?3. Why is every other frontier entry more expensive?\n```\n\nThose three questions are essentially the UCS algorithm.\n\n**Why DFS Could Make a Different Choice**\n\nThis is where UCS differs from DFS.\n\nDFS might follow one branch deeply:\n\n```\nSTART ↓A ↓C ↓G ↓TREASURE\n```\n\nIt has found a valid solution.\n\nBut that solution costs:\n\n```\n2 + 2 + 3 + 2 = 9\n```\n\nDFS doesn’t naturally stop and ask:\n\n“Is there another route that costs less?”\n\nUCS does.\n\nIt keeps the frontier ordered by accumulated cost.\n\nIn our graph, UCS eventually discovers:\n\n```\nSTART → A → D → G → TREASURECost = 6\n```\n\nSo DFS can find a solution without necessarily finding the cheapest solution.\n\nUCS is specifically designed to find the least-cost solution when the edge costs are non-negative.\n\n**What About BFS?**\n\nBFS gives us another useful comparison.\n\nBFS explores the graph level by level.\n\nThat means it generally finds a path with the fewest edges, not necessarily the lowest total cost.\n\nConsider these two routes:\n\n```\nRoute BSTART → A → D → G → TREASURE4 actionsCost = 2 + 1 + 1 + 2     = 6Route DSTART → B → F → I → TREASURE4 actionsCost = 1 + 1 + 2 + 4     = 8\n```\n\nBoth routes contain four edges.\n\nBFS has no reason to prefer one based on cost.\n\nUCS does.\n\nIt calculates:\n\n```\nRoute B = 6Route D = 8\n```\n\nand therefore prefers Route B.\n\nBut we can make the distinction even clearer by looking at routes with different numbers of steps.\n\n```\nRoute BSTART → A → D → G → TREASURE4 actionsCost = 6\n```\n\nversus:\n\n```\nSTART → B → F → I → TREASURE4 actionsCost = 8\n```\n\nThe number of steps alone tells us nothing about the actual cost.\n\nThis is the fundamental difference. BFS optimizes for step count. UCS optimizes for accumulated cost, and a longer path can still be the cheaper one.\n\nThis gives us a useful summary:\n\n**Algorithm**\n\n**What it primarily cares about**\n\nDFS\n\nGo deeper\n\nBFS\n\nFewest steps\n\nUCS\n\nLowest total cost\n\nThe distinction becomes important whenever different actions have different costs.\n\n**The Priority Queue**\n\nThe data structure behind UCS is a **min-priority queue**.\n\nConceptually, at one point in our search it might look like:\n\n```\n┌────────────────────────────────────────────┐│ Path                              Cost     │├────────────────────────────────────────────┤│ START → A → D                    3         ││ START → A → C                    4         ││ START → B → F → I                4         ││ START → B → E                    5         ││ START → A → D → H                5         │└────────────────────────────────────────────┘\n```\n\nThe search always takes the lowest-cost entry.\n\nIn Python, we can implement this using heapq:\n\n``` python\nimport heapqpriority_queue = []heapq.heappush(priority_queue, (0, \"START\"))while priority_queue:    cost, node = heapq.heappop(priority_queue)    print(node, cost)\n```\n\nThe important part isn’t the Python syntax.\n\nIt is the concept:\n\n```\npop → cheapest path\n```\n\nEvery time UCS has to decide what to explore next, it chooses the path with the smallest accumulated cost.\n\nOne small Python detail is worth knowing here: tuples such as (cost, node) work fine when node values are directly comparable, such as strings. If two entries have the same cost, heapq falls through to comparing the second element. If those values are incomparable, such as dictionaries, custom objects without ordering, or mixed types, Python can raise a TypeError.\n\nA standard fix is to add a monotonically increasing tiebreaker:\n\n```\n(cost, counter, node)\n```\n\n**A Simple UCS Implementation**\n\nWe can represent the graph in Python:\n\n```\ngraph = {    \"START\": [        (\"A\", 2),        (\"B\", 1)    ],    \"A\": [        (\"C\", 2),        (\"D\", 1)    ],    \"B\": [        (\"E\", 4),        (\"F\", 1)    ],    \"C\": [        (\"G\", 3)    ],    \"D\": [        (\"G\", 1),        (\"H\", 2)    ],    \"E\": [        (\"H\", 1)    ],    \"F\": [        (\"I\", 2)    ],    \"G\": [        (\"TREASURE\", 2)    ],    \"H\": [        (\"TREASURE\", 1)    ],    \"I\": [        (\"TREASURE\", 4)    ],    \"TREASURE\": []}\n```\n\nNow we can implement UCS:\n\n``` python\nimport heapqdef uniform_cost_search(graph, start, goal):    queue = [(0, start)]    visited = set()    while queue:        cost, node = heapq.heappop(queue)        if node in visited:            continue        visited.add(node)        if node == goal:            return cost        for next_node, edge_cost in graph[node]:            if next_node not in visited:                total_cost = cost + edge_cost                heapq.heappush(                    queue,                    (total_cost, next_node)                )    return None\n```\n\nThe important line is:\n\n```\ntotal_cost = cost + edge_cost\n```\n\nThe search carries the accumulated cost forward as it explores the graph.\n\nThat’s the heart of Uniform-Cost Search.\n\n**Why Is ****visited Marked on POP?**\n\nThere is a deliberate difference here from the DFS implementation we saw earlier.\n\nIn the DFS/BFS examples, we used the familiar rule of marking a node as visited before pushing it into the frontier.\n\nWith UCS, that would be unsafe.\n\nA node can be reached through multiple paths with different costs:\n\n```\nSTART → A → C       Cost = 10START → B → C       Cost = 6\n```\n\nIf we mark C visited when the first path pushes it into the queue, we could accidentally lock in the more expensive path.\n\nUCS instead waits until C is **popped from the priority queue**.\n\nBecause the priority queue always removes the lowest-cost entry first, the first time a node is popped, we know we are processing its cheapest discovered path under the non-negative-cost assumption.\n\nSo this is not an inconsistency with the DFS rule.\n\nIt is a deliberate consequence of using a **cost-ordered frontier**.\n\n**UCS Complexity**\n\nThere is a computational cost to this extra bookkeeping.\n\nWith a binary heap priority queue, UCS has a typical time complexity of:\n\n```\nO((V + E) log V)\n```\n\nwhere V is the number of vertices and E is the number of edges.\n\nDFS and BFS can operate in:\n\n```\nO(V + E)\n```\n\nbecause their stack/queue operations are constant-time in the usual implementation.\n\nUCS is slower because every push and pop involves maintaining the heap ordering.\n\nThis connects directly to the **visited-on-pop** behavior we just discussed.\n\nA node can be discovered through multiple paths, so UCS may push multiple candidate entries into the heap before one of them is finally popped and finalized.\n\nFor space complexity:\n\n```\nVisited set = O(V)Heap entries = O(E) in the worst caseTotal = O(V + E)\n```\n\nSo UCS gives us a stronger guarantee about cost, but that guarantee comes with additional computation and memory overhead.\n\n**One Important Limitation**\n\nUCS works under an important assumption: **action costs should not be negative**.\n\nHere’s why that matters.\n\nImagine UCS has already popped and finalized a node at cost 10:\n\n```\nSTART  |  | 10  ↓  A\n```\n\nLater, suppose the search discovers another route:\n\n```\nSTART  |  | 8  ↓  B  |  | -2  ↓  A\n```\n\nThat second route reaches A with:\n\n```\n8 + (-2) = 6\n```\n\nBut UCS has already popped A at cost 10 and marked it visited.\n\nIt won’t revisit A.\n\nSo it keeps the wrong answer:\n\n```\nFinalized cost = 10Actual cheaper cost = 6\n```\n\nThis is exactly why negative edges break the usual UCS optimality guarantee.\n\nWith non-negative costs, a cheaper path cannot suddenly appear later by adding a negative edge.\n\nIf A has already been popped at cost 10, any later path reaching A must have accumulated at least 10 before taking its final non-negative edge.\n\nSo the first popped path is safe to finalize.\n\n**Does UCS Guarantee the Best Solution?**\n\nUnder the standard conditions, including non-negative action costs, UCS guarantees that when it removes a goal from the priority queue, it has found a **least-cost path** to that goal.\n\nThat’s a powerful property.\n\nThe algorithm isn’t simply saying:\n\n“I found a path to the goal.”\n\nIt is saying:\n\n“Based on the cost model I was given, this is the cheapest path, and under the algorithm’s assumptions, it is optimal.”\n\nOf course, there is an important caveat.\n\nThe result is only as good as the **cost model**.\n\nIf we assign the wrong costs, UCS can faithfully find the wrong “best” solution.\n\nThe search algorithm can optimize the numbers we give it.\n\nIt cannot decide whether those numbers accurately represent the real world.\n\nThat’s an important lesson when applying classical algorithms to real-world problems.\n\n**Connecting UCS Back to PeopleSoft**\n\nNow let’s bring the idea back to the world we know.\n\nA PeopleSoft process can also be represented as a graph.\n\nFor example:\n\n```\nPeopleSoft State       ↓Possible Operations       ↓Different Costs       ↓Search       ↓Lowest-Cost Path       ↓Desired Business State\n```\n\nA node could represent a system state.\n\nAn edge could represent an operation.\n\nThe edge weight could represent execution time, processing effort, system impact, risk, or another measurable cost.\n\nThe important point is that UCS doesn’t need to understand PeopleSoft.\n\nIt doesn’t need to know what a component, process, voucher, integration, or business rule means.\n\nIt only needs:\n\n```\nCurrent statePossible next statesCost of each transitionGoal state\n```\n\nThat is an important idea when moving from enterprise software toward AI.\n\nWe don’t necessarily need to put AI inside the algorithm.\n\nWe first need to understand how a problem can be represented mathematically.\n\nOnce the problem is represented correctly, algorithms can operate on that representation.\n\n**Where UCS Fits in Our Journey**\n\nSo far, we’ve moved through three different ways of thinking about search:\n\n```\nBFS↓\"Find the solution using the fewest steps.\"DFS↓\"Go deep and see where this path takes me.\"UCS↓\"Find the solution with the lowest total cost.\"\n```\n\nAnd this progression is important.\n\nWe’re gradually moving from **blind exploration** toward **more informed decision-making**.\n\nDFS doesn’t care about cost.\n\nBFS cares about the number of steps.\n\nUCS cares about the accumulated cost.\n\nBut UCS still has a limitation.\n\nIt has no idea whether it is moving **toward the goal**.\n\nImagine our search space has thousands of possible states.\n\nUCS can correctly identify the cheapest paths so far, but it may spend a lot of time exploring cheap paths that ultimately lead nowhere useful.\n\nWhat if we could give the search a clue?\n\nWhat if it could estimate:\n\n“This state looks much closer to the goal than that one.”\n\nNow the search could become even more focused.\n\nAnd that leads us to the next step.\n\n**Coming Up Next**\n\nWe’ve now introduced **cost-aware search**.\n\nBut cost alone isn’t enough when the search space becomes large.\n\nOur search problem needs another piece of information: an estimate of **how promising a state is**.\n\nThat idea of using an estimate to guide the search is called a **heuristic**.\n\nIn the next article:\n\n**Part 17: Greedy Best-First Search — What If the AI Could Guess Which Path Looks Promising?**\n\nWe’ll see what happens when we stop looking only at the cost we’ve already paid and start using an estimate of where we should go next.\n\n**About This Series**\n\n**PeopleSoft to AI** documents my transition from ERP development to AI engineering.\n\nRather than treating AI and enterprise software as separate worlds, I’m exploring how the concepts I learn in AI connect with the systems I’ve spent nearly a decade building and supporting.\n\nThe goal isn’t to present myself as an AI expert. It’s to document the learning process honestly, connect theory with real enterprise scenarios, and hopefully make the journey a little easier for other ERP professionals who are curious about AI but aren’t sure where to begin.\n\n[PeopleSoft to AI | Part 16: Uniform-Cost Search — What If Every Action Has a Different Cost?](https://pub.towardsai.net/peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-different-cost-29598bc6d2bc) was originally published in [Towards AI](https://pub.towardsai.net) on Medium, where people are continuing the conversation by highlighting and responding to this story.", "url": "https://wpnews.pro/news/peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-cost", "canonical_source": "https://pub.towardsai.net/peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-different-cost-29598bc6d2bc?source=rss----98111c9905da---4", "published_at": "2026-08-25 06:00:20+00:00", "updated_at": "2026-08-25 06:13:48.075670+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning"], "entities": ["PeopleSoft", "Uniform-Cost Search (UCS)"], "alternates": {"html": "https://wpnews.pro/news/peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-cost", "markdown": "https://wpnews.pro/news/peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-cost.md", "text": "https://wpnews.pro/news/peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-cost.txt", "jsonld": "https://wpnews.pro/news/peoplesoft-to-ai-part-16-uniform-cost-search-what-if-every-action-has-a-cost.jsonld"}}