├── Classic ├── Graph │ ├── Graph.py │ ├── a_star.py │ ├── bfs.py │ ├── bi_bfs.py │ ├── dfs_limited.py │ ├── iterative_dfs.py │ ├── ucs.py │ └── unlimited_dfs.py └── Problem │ ├── a_star.py │ ├── bfs.py │ ├── bi_bfs.py │ ├── dfs_limited.py │ ├── iterative_dfs.py │ ├── ucs.py │ └── unlimited_dfs.py ├── Heuristic ├── first_choice_hill_climbing.py ├── genetic.py ├── hill_climbing.py ├── hill_climbing_stochastic.py ├── random_restart_hill_climbing.py ├── simulated_annealing.py └── stochastic_hill_climbing.py └── README.md /Classic/Graph/Graph.py: -------------------------------------------------------------------------------- 1 | class Graph: 2 | def __init__(self, graph, weight=None): 3 | self.edges = list() 4 | self.nodes = list() 5 | self.graph = graph 6 | self.generateEdges(graph, weight) 7 | self.generateNodes(graph) 8 | 9 | def generateEdges(self, graph, weight): 10 | if weight: 11 | for nodeIndex in range(len(graph)): 12 | for neighbourIndex in range(len(graph[nodeIndex])): 13 | self.edges.append((nodeIndex, graph[nodeIndex][neighbourIndex], weight[nodeIndex][neighbourIndex])) 14 | else: 15 | for nodeIndex in range(len(graph)): 16 | for neighbourIndex in range(len(graph[nodeIndex])): 17 | self.edges.append((nodeIndex, graph[nodeIndex][neighbourIndex], 0)) 18 | 19 | def generateNodes(self, arr): 20 | for i in range(len(arr)): 21 | self.nodes.append(i) 22 | 23 | def getCost(self, fromNode, toNode): 24 | for edge in self.edges: 25 | if edge[0] == fromNode and edge[1] == toNode: 26 | return edge[2] 27 | -------------------------------------------------------------------------------- /Classic/Graph/a_star.py: -------------------------------------------------------------------------------- 1 | import Graph 2 | def aStar(graph, startState, endState, h,isGraph): 3 | f = list() 4 | fWeight = list() 5 | e = list() 6 | nodePath = list() 7 | 8 | expandedNodes = 0 9 | seenNodes = 0 10 | maxH = 0 11 | 12 | try: 13 | f.append(startState) 14 | seenNodes += 1 15 | fWeight.append(h[startState]) 16 | nodePath.append([startState]) 17 | except: 18 | print "invalid start state" 19 | 20 | while f: 21 | minWeightIndex = fWeight.index(min(fWeight)) 22 | tempState = f.pop(minWeightIndex) 23 | tempCost = fWeight.pop(minWeightIndex) - h[tempState] 24 | tempPath = nodePath.pop(minWeightIndex) 25 | if tempState == endState: 26 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempPath, "cost": tempCost, "max memory": maxH} 27 | if isGraph: 28 | e.append(tempState) 29 | expandedNodes += 1 30 | for node in graph.graph[tempState]: 31 | if (isGraph and (node not in e)) or (not isGraph): 32 | cost = graph.getCost(tempState, node) + h[node] 33 | tempList = list(tempPath) 34 | tempList.append(node) 35 | 36 | if node in f: 37 | if cost + tempCost < fWeight[f.index(node)]: 38 | fWeight[f.index(node)] = cost + tempCost 39 | nodePath[f.index(node)] = tempList 40 | else: 41 | f.append(node) 42 | seenNodes += 1 43 | fWeight.append(cost + tempCost) 44 | nodePath.append(tempList) 45 | maxH = max(maxH, len(f)) 46 | 47 | # graph = [[1, 2, 5], [0, 2, 3], [0, 1, 3, 5], [1, 2, 4], [3, 5], [0, 2, 4]] 48 | # cost = [[7, 9, 14], [7, 10, 15], [9, 10, 11, 2], [15, 11, 6], [6, 9], [14, 2, 9]] 49 | # graph = [[1, 7], [0, 2, 7], [1, 3, 5, 8], [2, 4, 5], [3, 5], [2, 3, 4, 6], [5, 7, 8], [0, 1, 6, 8], [2, 6, 7]] 50 | # cost = [[4, 8], [4, 8, 11], [8, 7, 4, 2], [7, 9, 14], [9, 10], [4, 14, 10, 2], [2, 1, 6], [8, 11, 1, 7], [2, 6, 7]] 51 | graph = [[1, 2], [0, 3], [0, 4], [1, 5], [2, 6], [3, 6], [4, 5]] 52 | cost = [[1.5, 2], [1.5, 2], [2, 3], [2, 3], [3, 2], [3, 4], [2, 4]] 53 | h = [8, 4, 4.5, 2, 2, 4, 0] 54 | myGraph = Graph.Graph(graph, cost) 55 | print aStar(myGraph, 0, 6, h, False) -------------------------------------------------------------------------------- /Classic/Graph/bfs.py: -------------------------------------------------------------------------------- 1 | def bfs(graph, startState, endState, isGraph): 2 | f = list() 3 | e = list() 4 | nodePath = list() 5 | 6 | expandedNodes = 0 7 | seenNodes = 0 8 | cost = 0 9 | maxH = 0 10 | 11 | try: 12 | f.append(startState) 13 | seenNodes += 1 14 | nodePath.append([startState]) 15 | except: 16 | print "invalid start state" 17 | 18 | while f: 19 | tempState = f.pop(0) 20 | tempPath = nodePath.pop(0) 21 | if isGraph: 22 | e.append(tempState) 23 | expandedNodes += 1 24 | for node in graph[tempState]: 25 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 26 | tempList = list(tempPath) 27 | tempList.append(node) 28 | f.append(node) 29 | seenNodes += 1 30 | nodePath.append(tempList) 31 | if node == endState: 32 | maxH = max(maxH, len(f)) 33 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, "max memory": maxH} 34 | maxH = max(maxH, len(f)) 35 | 36 | # graph = [[], [3, 4, 2], [5], [1], [1], [9, 10, 8], [], [], [], [], [], []] 37 | # graph = [[1, 2], [0, 3], [0, 4], [1, 5], [2, 6], [3, 6], [4, 5]] 38 | graph = [[], [2, 3, 4, 8], [5], [6, 7, 10], [8], [9, 10], [], [], [], [], [], []] 39 | 40 | print bfs(graph, 1, 6, False) -------------------------------------------------------------------------------- /Classic/Graph/bi_bfs.py: -------------------------------------------------------------------------------- 1 | def bi_bfs(graph, startState, endState, isGraph): 2 | fR = list() 3 | eR = list() 4 | nodePathR = list() 5 | 6 | fB = list() 7 | eB = list() 8 | nodePathB = list() 9 | 10 | expandedNodes = 0 11 | seenNodes = 0 12 | cost = 0 13 | maxH = 0 14 | 15 | try: 16 | fR.append(startState) 17 | seenNodes += 1 18 | nodePathR.append([startState]) 19 | 20 | fB.append(endState) 21 | seenNodes += 1 22 | nodePathB.append([endState]) 23 | except: 24 | print "invalid start state" 25 | 26 | while fR or fB: 27 | if fR: 28 | tempState = fR.pop(0) 29 | expandedNodes += 1 30 | tempPath = nodePathR.pop(0) 31 | if isGraph: 32 | eR.append(tempState) 33 | for node in graph[tempState]: 34 | if (isGraph and (node not in eR and node not in fR)) or (not isGraph): 35 | tempList = list(tempPath) 36 | tempList.append(node) 37 | fR.append(node) 38 | seenNodes += 1 39 | nodePathR.append(tempList) 40 | if node == endState: 41 | maxH = max(maxH, len(fR) + len(fB)) 42 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, "max memory": maxH} 43 | for node in fR: 44 | if node in fB: 45 | s = nodePathB[fB.index(node)] 46 | s = s[: len(s) - 1] 47 | maxH = max(maxH, len(fR) + len(fB)) 48 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePathR[fR.index(node)] + list(reversed(s)), "cost": cost, "max memory": maxH} 49 | maxH = max(maxH, len(fR) + len(fB)) 50 | if fB: 51 | tempState = fB.pop(0) 52 | tempPath = nodePathB.pop(0) 53 | if isGraph: 54 | eB.append(tempState) 55 | expandedNodes += 1 56 | for node in graph[tempState]: 57 | if (isGraph and (node not in eB and node not in fB)) or (not isGraph): 58 | tempList = list(tempPath) 59 | tempList.append(node) 60 | fB.append(node) 61 | seenNodes += 1 62 | nodePathB.append(tempList) 63 | maxH = max(maxH, len(fR) + len(fB)) 64 | if node == startState: 65 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, "max memory": maxH} 66 | for node in fR: 67 | if node in fB: 68 | s = nodePathB[fB.index(node)] 69 | s = s[: len(s) - 1] 70 | maxH = max(maxH, len(fR) + len(fB)) 71 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePathR[fR.index(node)] + list(reversed(s)), "cost": cost, "max memory": maxH} 72 | maxH = max(maxH, len(fR) + len(fB)) 73 | 74 | # graph = [[1, 7], [0, 2, 7], [1, 3, 5, 8], [2, 4, 5], [3, 5], [2, 3, 4, 6], [5, 7, 8], [0, 1, 6, 8], [2, 6, 7]] 75 | # graph = [[], [3, 4, 2], [5], [1], [1], [9, 10, 8], [], [], [], [], [], []] 76 | # graph = [[], [2, 3, 4, 8], [5], [6, 7, 10], [8], [9, 10], [], [], [], [], [], []] 77 | graph = [[1, 7], [0, 2, 7], [1, 3, 5, 8], [2, 4, 5], [3, 5], [2, 3, 4, 6], [5, 7, 8], [0, 1, 6, 8], [2, 6, 7]] 78 | 79 | print bi_bfs(graph, 0, 8, True) -------------------------------------------------------------------------------- /Classic/Graph/dfs_limited.py: -------------------------------------------------------------------------------- 1 | def dfsLimited(graph, startState, endState, l, isGraph): 2 | f = list() 3 | e = list() 4 | nodePath = list() 5 | 6 | expandedNodes = 0 7 | seenNodes = 0 8 | cost = 0 9 | maxH = 0 10 | 11 | try: 12 | f.append(startState) 13 | seenNodes += 1 14 | nodePath.append([startState]) 15 | except: 16 | print "invalid start state" 17 | 18 | while f: 19 | tempState = f.pop(0) 20 | tempPath = nodePath.pop(0) 21 | if len(tempPath) >= l: 22 | continue 23 | if isGraph: 24 | e.append(tempState) 25 | expandedNodes += 1 26 | count = 0 27 | for node in graph[tempState]: 28 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 29 | tempList = list(tempPath) 30 | tempList.append(node) 31 | f.insert(0 + count, node) 32 | seenNodes += 1 33 | nodePath.insert(0 + count, tempList) 34 | count += 1 35 | if node == endState: 36 | maxH = max(maxH, len(f)) 37 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, "max memory": maxH} 38 | maxH = max(maxH, len(f)) 39 | 40 | graph = [[], [3, 4, 2], [5], [1], [1], [9, 10, 8], [], [], [], [], [], []] 41 | # graph = [[], [2, 3, 4, 8], [5], [6, 7, 10], [8], [9, 10], [], [], [], [], [], []] 42 | 43 | print dfsLimited(graph, 1, 10, 4, True) -------------------------------------------------------------------------------- /Classic/Graph/iterative_dfs.py: -------------------------------------------------------------------------------- 1 | def dfsIterative(graph, startState, endState, isGraph): 2 | l = 1 3 | 4 | expandedNodes = 0 5 | seenNodes = 0 6 | cost = 0 7 | maxH = 0 8 | while True: 9 | f = list() 10 | e = list() 11 | nodePath = list() 12 | 13 | try: 14 | f.append(startState) 15 | seenNodes += 1 16 | nodePath.append([startState]) 17 | except: 18 | print "invalid start state" 19 | 20 | while f: 21 | tempState = f.pop(0) 22 | tempPath = nodePath.pop(0) 23 | if len(tempPath) >= l: 24 | continue 25 | if isGraph: 26 | e.append(tempState) 27 | expandedNodes += 1 28 | count = 0 29 | for node in graph[tempState]: 30 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 31 | tempList = list(tempPath) 32 | tempList.append(node) 33 | f.insert(0 + count, node) 34 | seenNodes += 1 35 | nodePath.insert(0 + count, tempList) 36 | count += 1 37 | if node == endState: 38 | maxH = max(maxH, len(f)) 39 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, "max memory": maxH} 40 | maxH = max(maxH, len(f)) 41 | l += 1 42 | 43 | 44 | graph = [[], [3, 4, 2], [5], [1], [1], [9, 10, 8], [], [], [], [], [], []] 45 | # graph = [[], [2, 3, 4, 8], [5], [6, 7, 10], [8], [9, 10], [], [], [], [], [], []] 46 | 47 | print dfsIterative(graph, 1, 8, True) -------------------------------------------------------------------------------- /Classic/Graph/ucs.py: -------------------------------------------------------------------------------- 1 | import Graph 2 | def ucs(graph, startState, endState, isGraph): 3 | f = list() 4 | fWeight = list() 5 | e = list() 6 | nodePath = list() 7 | 8 | expandedNodes = 0 9 | seenNodes = 0 10 | maxH = 0 11 | 12 | try: 13 | f.append(startState) 14 | seenNodes +=1 15 | fWeight.append(0) 16 | nodePath.append([startState]) 17 | except: 18 | print "invalid start state" 19 | 20 | while f: 21 | minWeightIndex = fWeight.index(min(fWeight)) 22 | tempState = f.pop(minWeightIndex) 23 | tempCost = fWeight.pop(minWeightIndex) 24 | tempPath = nodePath.pop(minWeightIndex) 25 | if tempState == endState: 26 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempPath, "cost": tempCost, "max memory": maxH} 27 | if isGraph: 28 | e.append(tempState) 29 | expandedNodes += 1 30 | for node in graph.graph[tempState]: 31 | if (isGraph and (node not in e)) or (not isGraph): 32 | cost = graph.getCost(tempState, node) 33 | tempList = list(tempPath) 34 | tempList.append(node) 35 | if node in f: 36 | if cost + tempCost < fWeight[f.index(node)]: 37 | fWeight[f.index(node)] = cost + tempCost 38 | nodePath[f.index(node)] = tempList 39 | else: 40 | f.append(node) 41 | seenNodes += 1 42 | fWeight.append(cost + tempCost) 43 | nodePath.append(tempList) 44 | 45 | maxH = maxH = max(maxH, len(f)) 46 | 47 | # graph = [[1, 2, 5], [0, 2, 3], [0, 1, 3, 5], [1, 2, 4], [3, 5], [0, 2, 4]] 48 | # cost = [[7, 9, 14], [7, 10, 15], [9, 10, 11, 2], [15, 11, 6], [6, 9], [14, 2, 9]] 49 | 50 | graph = [[1, 7], [0, 2, 7], [1, 3, 5, 8], [2, 4, 5], [3, 5], [2, 3, 4, 6], [5, 7, 8], [0, 1, 6, 8], [2, 6, 7]] 51 | cost = [[4, 8], [4, 8, 11], [8, 7, 4, 2], [7, 9, 14], [9, 10], [4, 14, 10, 2], [2, 1, 6], [8, 11, 1, 7], [2, 6, 7]] 52 | 53 | myGraph = Graph.Graph(graph, cost) 54 | print ucs(myGraph, 0, 8, False) -------------------------------------------------------------------------------- /Classic/Graph/unlimited_dfs.py: -------------------------------------------------------------------------------- 1 | def dfsUnlimited(graph, startState, endState, isGraph): 2 | f = list() 3 | e = list() 4 | nodePath = list() 5 | 6 | expandedNodes = 0 7 | seenNodes = 0 8 | cost = 0 9 | maxH = 0 10 | 11 | try: 12 | f.append(startState) 13 | seenNodes += 1 14 | nodePath.append([startState]) 15 | except: 16 | print "invalid start state" 17 | 18 | while f: 19 | tempState = f.pop(0) 20 | tempPath = nodePath.pop(0) 21 | if isGraph: 22 | e.append(tempState) 23 | expandedNodes += 1 24 | count = 0 25 | for node in graph[tempState]: 26 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 27 | tempList = list(tempPath) 28 | tempList.append(node) 29 | f.insert(0 + count, node) 30 | seenNodes += 1 31 | nodePath.insert(0 + count, tempList) 32 | maxH = max(maxH, len(f)) 33 | count += 1 34 | if node == endState: 35 | maxH = max(maxH, len(f)) 36 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, "max memory": maxH} 37 | maxH = max(maxH, len(f)) 38 | 39 | graph = [[], [3, 4, 2], [5], [1], [1], [9, 10, 8], [], [], [], [], [], []] 40 | # graph = [[], [2, 3, 4, 8], [5], [6, 7, 10], [8], [9, 10], [], [], [], [], [], []] 41 | 42 | print dfsUnlimited(graph, 1, 10, True) -------------------------------------------------------------------------------- /Classic/Problem/a_star.py: -------------------------------------------------------------------------------- 1 | def aStar(problem, isGraph): 2 | startState = problem.initialState() 3 | f = list() 4 | fWeight = list() 5 | e = list() 6 | nodePath = list() 7 | tempState = startState 8 | 9 | expandedNodes = 0 10 | seenNodes = 0 11 | maxH = 0 12 | 13 | try: 14 | f.append(startState) 15 | seenNodes += 1 16 | fWeight.append(problem.heuristic(startState)) 17 | nodePath.append([startState]) 18 | except: 19 | print "invalid start state" 20 | 21 | while f: 22 | minWeightIndex = fWeight.index(min(fWeight)) 23 | tempState = problem.result(tempState, f.pop(minWeightIndex)) 24 | tempCost = fWeight.pop(minWeightIndex) - problem.heuristic(tempState) 25 | tempPath = nodePath.pop(minWeightIndex) 26 | if problem.goalTest(tempState): 27 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempPath, "cost": tempCost, 28 | "max memory": maxH} 29 | if isGraph: 30 | e.append(tempState) 31 | expandedNodes += 1 32 | neighbors = problem.actions(tempState) 33 | for node in neighbors: 34 | if (isGraph and (node not in e)) or (not isGraph): 35 | cost = problem.pathCost(tempState, node) + problem.heuristic(node) 36 | tempList = list(tempPath) 37 | tempList.append(node) 38 | if node in f: 39 | if cost + tempCost < fWeight[f.index(node)]: 40 | fWeight[f.index(node)] = cost + tempCost 41 | nodePath[f.index(node)] = tempList 42 | else: 43 | f.append(node) 44 | seenNodes += 1 45 | fWeight.append(cost + tempCost) 46 | nodePath.append(tempList) 47 | maxH = max(maxH, len(f)) 48 | -------------------------------------------------------------------------------- /Classic/Problem/bfs.py: -------------------------------------------------------------------------------- 1 | def bfs(problem, isGraph): 2 | startState = problem.initialState() 3 | f = list() 4 | e = list() 5 | nodePath = list() 6 | expandedNodes = 0 7 | seenNodes = 0 8 | cost = 0 9 | maxH = 0 10 | tempState = startState 11 | 12 | try: 13 | f.append(startState) 14 | seenNodes += 1 15 | nodePath.append([startState]) 16 | except: 17 | print "invalid start state" 18 | 19 | while f: 20 | tempState = problem.result(tempState, f.pop(0)) 21 | tempPath = nodePath.pop(0) 22 | if isGraph: 23 | e.append(tempState) 24 | expandedNodes += 1 25 | neighbors = problem.actions(tempState) 26 | for node in neighbors: 27 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 28 | tempList = list(tempPath) 29 | tempList.append(node) 30 | f.append(node) 31 | seenNodes += 1 32 | nodePath.append(tempList) 33 | if problem.goalTest(node): 34 | maxH = max(maxH, len(f)) 35 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, 36 | "max memory": maxH} 37 | maxH = max(maxH, len(f)) 38 | -------------------------------------------------------------------------------- /Classic/Problem/bi_bfs.py: -------------------------------------------------------------------------------- 1 | def biBfs(problem, isGraph): 2 | startState = problem.initialState() 3 | endState = problem.getGoalState() 4 | fR = list() 5 | eR = list() 6 | nodePathR = list() 7 | tempStateR = startState 8 | 9 | fB = list() 10 | eB = list() 11 | nodePathB = list() 12 | tempStateB = endState 13 | 14 | expandedNodes = 0 15 | seenNodes = 0 16 | cost = 0 17 | maxH = 0 18 | 19 | try: 20 | fR.append(startState) 21 | seenNodes += 1 22 | nodePathR.append([startState]) 23 | 24 | fB.append(endState) 25 | seenNodes += 1 26 | nodePathB.append([endState]) 27 | 28 | except: 29 | print "invalid start state" 30 | 31 | while fR or fB: 32 | if fR: 33 | tempStateR = problem.result(tempStateR, fR.pop(0)) 34 | expandedNodes += 1 35 | tempPath = nodePathR.pop(0) 36 | if isGraph: 37 | eR.append(tempStateR) 38 | neighbors = problem.actions(tempStateR) 39 | for node in neighbors: 40 | if (isGraph and (node not in eR and node not in fR)) or (not isGraph): 41 | tempList = list(tempPath) 42 | tempList.append(node) 43 | fR.append(node) 44 | seenNodes += 1 45 | nodePathR.append(tempList) 46 | 47 | if problem.goalTest(node): 48 | maxH = max(maxH, len(fR) + len(fB)) 49 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, 50 | "max memory": maxH} 51 | for node in fR: 52 | if node in fB: 53 | s = nodePathB[fB.index(node)] 54 | s = s[: len(s) - 1] 55 | maxH = max(maxH, len(fR) + len(fB)) 56 | return {"seen": seenNodes, "expanded": expandedNodes, 57 | "route": nodePathR[fR.index(node)] + list(reversed(s)), "cost": cost, "max memory": maxH} 58 | maxH = max(maxH, len(fR) + len(fB)) 59 | if fB: 60 | tempStateB = problem.result(tempStateB, fB.pop(0)) 61 | tempPath = nodePathB.pop(0) 62 | if isGraph: 63 | eB.append(tempStateB) 64 | expandedNodes += 1 65 | neighbors = problem.actions(tempStateB) 66 | for node in neighbors: 67 | if (isGraph and (node not in eB and node not in fB)) or (not isGraph): 68 | tempList = list(tempPath) 69 | tempList.append(node) 70 | fB.append(node) 71 | seenNodes += 1 72 | nodePathB.append(tempList) 73 | 74 | maxH = max(maxH, len(fR) + len(fB)) 75 | if problem.goalTest(node, True): 76 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, 77 | "max memory": maxH} 78 | for node in fR: 79 | if node in fB: 80 | s = nodePathB[fB.index(node)] 81 | s = s[: len(s) - 1] 82 | maxH = max(maxH, len(fR) + len(fB)) 83 | return {"seen": seenNodes, "expanded": expandedNodes, 84 | "route": nodePathR[fR.index(node)] + list(reversed(s)), "cost": cost, "max memory": maxH} 85 | maxH = max(maxH, len(fR) + len(fB)) 86 | -------------------------------------------------------------------------------- /Classic/Problem/dfs_limited.py: -------------------------------------------------------------------------------- 1 | def dfsLimited(problem, l, isGraph): 2 | f = list() 3 | e = list() 4 | startState = problem.initialState() 5 | nodePath = list() 6 | 7 | expandedNodes = 0 8 | seenNodes = 0 9 | cost = 0 10 | maxH = 0 11 | tempState = startState 12 | 13 | try: 14 | f.append(startState) 15 | seenNodes += 1 16 | nodePath.append([startState]) 17 | except: 18 | print "invalid start state" 19 | 20 | while f: 21 | tempState = problem.result(tempState, f.pop(0)) 22 | tempPath = nodePath.pop(0) 23 | if len(tempPath) >= l: 24 | continue 25 | if isGraph: 26 | e.append(tempState) 27 | expandedNodes += 1 28 | neighbors = problem.actions(tempState) 29 | count = 0 30 | for node in neighbors: 31 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 32 | tempList = list(tempPath) 33 | tempList.append(node) 34 | f.insert(0 + count, node) 35 | seenNodes += 1 36 | nodePath.insert(0 + count, tempList) 37 | count += 1 38 | if problem.goalTest(node): 39 | maxH = max(maxH, len(f)) 40 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, 41 | "max memory": maxH} 42 | maxH = max(maxH, len(f)) 43 | -------------------------------------------------------------------------------- /Classic/Problem/iterative_dfs.py: -------------------------------------------------------------------------------- 1 | def dfsIterative(problem, isGraph): 2 | l = 1 3 | 4 | startState = problem.initialState() 5 | expandedNodes = 0 6 | seenNodes = 0 7 | cost = 0 8 | maxH = 0 9 | tempState = startState 10 | while True: 11 | f = list() 12 | e = list() 13 | nodePath = list() 14 | 15 | try: 16 | f.append(startState) 17 | seenNodes += 1 18 | nodePath.append([startState]) 19 | 20 | except: 21 | print "invalid start state" 22 | 23 | while f: 24 | tempState = problem.result(tempState, f.pop(0)) 25 | tempPath = nodePath.pop(0) 26 | if len(tempPath) >= l: 27 | continue 28 | if isGraph: 29 | e.append(tempState) 30 | expandedNodes += 1 31 | neighbors = problem.actions(tempState) 32 | count = 0 33 | for node in neighbors: 34 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 35 | tempList = list(tempPath) 36 | tempList.append(node) 37 | f.insert(0 + count, node) 38 | seenNodes += 1 39 | nodePath.insert(0 + count, tempList) 40 | count += 1 41 | if problem.goalTest(node): 42 | maxH = max(maxH, len(f)) 43 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, 44 | "max memory": maxH} 45 | maxH = max(maxH, len(f)) 46 | l += 1 47 | -------------------------------------------------------------------------------- /Classic/Problem/ucs.py: -------------------------------------------------------------------------------- 1 | def ucs(problem, isGraph): 2 | startState = problem.initialState() 3 | f = list() 4 | fWeight = list() 5 | e = list() 6 | nodePath = list() 7 | tempState = startState 8 | 9 | expandedNodes = 0 10 | seenNodes = 0 11 | maxH = 0 12 | 13 | try: 14 | f.append(startState) 15 | seenNodes += 1 16 | fWeight.append(0) 17 | nodePath.append([startState]) 18 | except: 19 | print "invalid start state" 20 | 21 | while f: 22 | minWeightIndex = fWeight.index(min(fWeight)) 23 | tempState = problem.result(tempState, f.pop(minWeightIndex)) 24 | tempCost = fWeight.pop(minWeightIndex) 25 | tempPath = nodePath.pop(minWeightIndex) 26 | if problem.goalTest(tempState): 27 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempPath, "cost": tempCost, 28 | "max memory": maxH} 29 | if isGraph: 30 | e.append(tempState) 31 | expandedNodes += 1 32 | neighbors = problem.actions(tempState) 33 | for node in neighbors: 34 | if (isGraph and (node not in e)) or (not isGraph): 35 | cost = problem.pathCost(tempState, node) 36 | tempList = list(tempPath) 37 | tempList.append(node) 38 | if node in f: 39 | if cost + tempCost < fWeight[f.index(node)]: 40 | fWeight[f.index(node)] = cost + tempCost 41 | nodePath[f.index(node)] = tempList 42 | else: 43 | f.append(node) 44 | seenNodes += 1 45 | fWeight.append(cost + tempCost) 46 | nodePath.append(tempList) 47 | maxH = max(maxH, len(f)) 48 | -------------------------------------------------------------------------------- /Classic/Problem/unlimited_dfs.py: -------------------------------------------------------------------------------- 1 | def dfsUnlimited(problem, isGraph): 2 | startState = problem.initialState() 3 | f = list() 4 | e = list() 5 | nodePath = list() 6 | 7 | expandedNodes = 0 8 | seenNodes = 0 9 | cost = 0 10 | maxH = 0 11 | tempState = startState 12 | 13 | try: 14 | f.append(startState) 15 | seenNodes += 1 16 | nodePath.append([startState]) 17 | except: 18 | print "invalid start state" 19 | 20 | while f: 21 | tempState = problem.result(tempState, f.pop(0)) 22 | tempPath = nodePath.pop(0) 23 | if isGraph: 24 | e.append(tempState) 25 | expandedNodes += 1 26 | neighbors = problem.actions(tempState) 27 | count = 0 28 | for node in neighbors: 29 | if (isGraph and (node not in e and node not in f)) or (not isGraph): 30 | tempList = list(tempPath) 31 | tempList.append(node) 32 | f.insert(0 + count, node) 33 | seenNodes += 1 34 | nodePath.insert(0 + count, tempList) 35 | count += 1 36 | if problem.goalTest(node): 37 | maxH = max(maxH, len(f)) 38 | return {"seen": seenNodes, "expanded": expandedNodes, "route": tempList, "cost": cost, 39 | "max memory": maxH} 40 | maxH = max(maxH, len(f)) 41 | -------------------------------------------------------------------------------- /Heuristic/first_choice_hill_climbing.py: -------------------------------------------------------------------------------- 1 | def hillClimbingFirstChoice(problem): 2 | nodePath = list() 3 | currentState = problem.initialState() 4 | 5 | expandedNodes = 0 6 | seenNodes = 0 7 | 8 | while True: 9 | nodePath.append(currentState) 10 | if problem.goalTest(currentState): 11 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "fitness": problem.getFitness()[currentState]} 12 | nextState, nextFitness, lenNeighbors = problem.generateRandomState(currentState) 13 | expandedNodes += 1 14 | seenNodes += lenNeighbors 15 | if nextFitness > problem.getFitness()[currentState]: 16 | currentState = nextState 17 | -------------------------------------------------------------------------------- /Heuristic/genetic.py: -------------------------------------------------------------------------------- 1 | # state formats : [[1, 2, 3], [1, 0, 3], ...] 2 | def genetic(problem, numberOfRepeat, n, mutationProb): 3 | counter = 0 4 | maxFitnessOutput = list() 5 | minFitnessOutput = list() 6 | avrageFitnessOutput = list() 7 | def mutate(cc): 8 | # just mutate the states with numbers 9 | pos = random.randrange(len(cc)) 10 | num = random.randrange(max(cc) + 1) 11 | cc[pos] = num 12 | return cc 13 | 14 | individual = list() 15 | 16 | doMutationList = list() 17 | l = 100 18 | k = math.ceil(mutationProb * l) 19 | for j in range(l): 20 | if j >= k: 21 | doMutationList.append(False) 22 | else: 23 | doMutationList.append(True) 24 | 25 | for i in range(n): 26 | while True: 27 | tmp = random.choice(problem.getGeneratedNumbers()) 28 | if tmp not in individual: 29 | individual.append(tmp) 30 | break 31 | else: 32 | continue 33 | 34 | while numberOfRepeat > 0: 35 | if problem.getGoal() in individual: 36 | print "best answer" 37 | print "number of repeats:", counter 38 | return {"individual": individual, "maxFitness": maxFitnessOutput, "minFitness": minFitnessOutput, "averageFitness": avrageFitnessOutput} 39 | prob = list() 40 | parents = list() 41 | individualFitness = list() 42 | fitnessMaxes = list() 43 | individualMaxes = list() 44 | 45 | print "individual:", individual 46 | for i in individual: 47 | individualFitness.append(problem.getFitness()[problem.getGeneratedNumbers().index(i)]) 48 | 49 | print "fitness:", individualFitness 50 | for i in range(len(individualFitness)): 51 | for j in range(individualFitness[i]): 52 | prob.append(i) 53 | 54 | for i in range(n): 55 | parents.append(individual[random.choice(prob)]) 56 | print "parents:", parents 57 | 58 | if n % 2 != 0: 59 | child = list(random.choice(parents)) 60 | parents.remove(child) 61 | doMutation = random.choice(doMutationList) 62 | if doMutation: 63 | child = list(mutate(child)) 64 | if child in problem.getGeneratedNumbers(): 65 | individual.append(child) 66 | individualFitness.append(problem.getFitness()[problem.getGeneratedNumbers().index(child)]) 67 | if n == 1: 68 | maxFitnessOutput.append(max(individualFitness)) 69 | minFitnessOutput.append(min(individualFitness)) 70 | avrageFitnessOutput.append(sum(individualFitness) / float(len(individualFitness))) 71 | print "max fitness:", max(individualFitness) 72 | print "min fitness:", min(individualFitness) 73 | print "max fitness:", sum(individualFitness) / float(len(individualFitness)) 74 | for i in xrange(0, len(parents), 2): 75 | cr1 = list(parents[i]) 76 | cr2 = list(parents[i + 1]) 77 | crPos = random.randrange(len(cr1)) 78 | 79 | child1 = list(cr1[:crPos] + cr2[crPos:]) 80 | doMutation = random.choice(doMutationList) 81 | if doMutation: 82 | child1 = list(mutate(child1)) 83 | child2 = list(cr2[:crPos] + cr1[crPos:]) 84 | doMutation = random.choice(doMutationList) 85 | if doMutation: 86 | child2 = list(mutate(child2)) 87 | 88 | if child1 in problem.getGeneratedNumbers(): 89 | individual.append(child1) 90 | individualFitness.append(problem.getFitness()[problem.getGeneratedNumbers().index(child1)]) 91 | if child2 in problem.getGeneratedNumbers(): 92 | individual.append(child2) 93 | individualFitness.append(problem.getFitness()[problem.getGeneratedNumbers().index(child2)]) 94 | maxFitnessOutput.append(max(individualFitness)) 95 | minFitnessOutput.append(min(individualFitness)) 96 | avrageFitnessOutput.append(sum(individualFitness) / float(len(individualFitness))) 97 | print "max fitness:", max(individualFitness) 98 | print "min fitness:", min(individualFitness) 99 | print "max fitness:", sum(individualFitness) / float(len(individualFitness)) 100 | print "cr1:", cr1 101 | print "cr2:", cr2 102 | print "child1:", child1 103 | print "child2:", child2 104 | 105 | for j in range(n): 106 | maxFitness = max(individualFitness) 107 | maxIndex = individualFitness.index(maxFitness) 108 | maxIndividual = individual[maxIndex] 109 | fitnessMaxes.append(maxFitness) 110 | individualFitness.remove(maxFitness) 111 | individualMaxes.append(maxIndividual) 112 | individual.remove(maxIndividual) 113 | 114 | numberOfRepeat -= 1 115 | counter += 1 116 | individualFitness = list(fitnessMaxes) 117 | individual = list(individualMaxes) 118 | print "individual: ", individual 119 | print "fitness: ", individualFitness, "\n" 120 | 121 | print "" 122 | return {"individual": individual, "maxFitness": maxFitnessOutput, "minFitness": minFitnessOutput, 123 | "averageFitness": avrageFitnessOutput} 124 | -------------------------------------------------------------------------------- /Heuristic/hill_climbing.py: -------------------------------------------------------------------------------- 1 | def hillClimbingSimple(problem): 2 | nodePath = list() 3 | currentState = problem.initialState() 4 | 5 | expandedNodes = 0 6 | seenNodes = 0 7 | 8 | while True: 9 | neighbors = problem.actions(currentState) 10 | nodePath.append(currentState) 11 | if problem.goalTest(currentState): 12 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "fitness": problem.getFitness()[currentState]} 13 | counter = 0 14 | expandedNodes += 1 15 | for node in neighbors: 16 | seenNodes += 1 17 | if problem.getFitness()[node] > problem.getFitness()[currentState]: 18 | currentState = node 19 | counter += 1 20 | if counter == 0: 21 | print "Local" 22 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "fitness": problem.getFitness()[currentState]} 23 | -------------------------------------------------------------------------------- /Heuristic/hill_climbing_stochastic.py: -------------------------------------------------------------------------------- 1 | def hillClimbingFirstChoice(problem): 2 | nodePath = list() 3 | currentState = problem.initialState() 4 | 5 | expandedNodes = 0 6 | seenNodes = 0 7 | 8 | while True: 9 | nodePath.append(currentState) 10 | if problem.goalTest(currentState): 11 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "fitness": problem.getFitness()[currentState]} 12 | nextState, nextFitness, lenNeighbors = problem.generateRandomState(currentState) 13 | expandedNodes += 1 14 | seenNodes += lenNeighbors 15 | if nextFitness > problem.getFitness()[currentState]: 16 | currentState = nextState 17 | -------------------------------------------------------------------------------- /Heuristic/random_restart_hill_climbing.py: -------------------------------------------------------------------------------- 1 | def hillClimbingRandomRestart(problem): 2 | nodePath = list() 3 | currentState = problem.initialState() 4 | 5 | expandedNodes = 0 6 | seenNodes = 0 7 | cost = 0 8 | 9 | while True: 10 | neighbors = problem.actions(currentState) 11 | nodePath.append(currentState) 12 | expandedNodes += 1 13 | if problem.goalTest(currentState): 14 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "cost": cost} 15 | counter = 0 16 | for node in neighbors: 17 | seenNodes += 1 18 | if problem.getFitness()[node] > problem.getFitness()[currentState]: 19 | currentState = node 20 | counter += 1 21 | if counter == 0: 22 | currentState = random.randint(0, len(problem.graph.graph) - 1) 23 | -------------------------------------------------------------------------------- /Heuristic/simulated_annealing.py: -------------------------------------------------------------------------------- 1 | import random 2 | import math 3 | 4 | 5 | def sa(problem, tempreature): 6 | nodePath = list() 7 | startState = problem.initialState() 8 | currentState = startState 9 | 10 | expandedNodes = 0 11 | seenNodes = 0 12 | 13 | while tempreature > 0: 14 | neighbors = problem.actions(currentState) 15 | nextState = random.choice(neighbors) 16 | delta = problem.getFitness()[nextState] - problem.getFitness()[currentState] 17 | nodePath.append(currentState) 18 | expandedNodes += 1 19 | seenNodes += len(neighbors) 20 | 21 | if problem.goalTest(currentState): 22 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "fitness": problem.getFitness()[currentState]} 23 | 24 | if delta > 0: 25 | currentState = nextState 26 | else: 27 | # p = math.exp(delta / float(tempreature)) 28 | # p = 1 / float(tempreature) 29 | p = random.uniform(0, 1) 30 | tmp = list() 31 | l = 100 32 | k = math.ceil(p * l) 33 | for i in range(l): 34 | if i >= k: 35 | tmp.append(nextState) 36 | else: 37 | tmp.append(currentState) 38 | currentState = random.choice(tmp) 39 | tempreature -= 1 -------------------------------------------------------------------------------- /Heuristic/stochastic_hill_climbing.py: -------------------------------------------------------------------------------- 1 | def hillClimbingStochastic(problem): 2 | nodePath = list() 3 | currentState = problem.initialState() 4 | 5 | expandedNodes = 0 6 | seenNodes = 0 7 | 8 | while True: 9 | neighbors = problem.actions(currentState) 10 | nodePath.append(currentState) 11 | counter = 0 12 | bestList = list() 13 | expandedNodes += 1 14 | for node in neighbors: 15 | seenNodes += 1 16 | if problem.getFitness()[node] > problem.getFitness()[currentState]: 17 | bestList.append(node) 18 | counter += 1 19 | if problem.goalTest(currentState): 20 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "fitness": problem.getFitness()[currentState]} 21 | if counter == 0: 22 | print "Local" 23 | return {"seen": seenNodes, "expanded": expandedNodes, "route": nodePath, "fitness": problem.getFitness()[currentState]} 24 | currentState = random.choice(bestList) 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Artificial Intelligence Search Algorithms 2 | AI search algorithms with graph and program implementation 3 | 4 | 5 | * Classic 6 | * A - Star 7 | * Breadth Frst Search (BFS) 8 | * Bidirectional Breadth First Search 9 | * Unlimitied Depth First Search (DFS) 10 | * Depth Limited First Search 11 | * Iterative Deepening Depth First Search (IDS) 12 | * Uniform Cost Search (UCS) 13 | * Heuristic 14 | * Simulated Annealing 15 | * Hill Climbing 16 | * Stochastic Hill Climbing 17 | * Random Restart Hill Climbing 18 | * First Choice Hill Climbing 19 | * Genetic 20 | --------------------------------------------------------------------------------