dsa.graph API documentation

# Module `dsa.graph`

## Functions

`def find_path(start, end, debug=False)`

  Return the shortest path of two vertices using Dijkstra's Algorithm.

  ## Args

  `start`
    starting vertex
  `end`
    ending vertex
  `debug`
    if True, display the weight table

  Returns: A list of vertices that form a shortest path

`def shortest_path(start, end, debug=False)`

  Helper function that returns a weight table and a previous vertex table using Dijkstra's Algorithm.

  ## Args

  `start`
    starting vertex
  `end`
    ending vertex
  `debug`
    if True, display weight table as it is being built

  Returns: a tuple of a weight table dictionary and a previous path dictionary

## Classes

`class AdjacencyMatrixGraph (labels: list[str])`

  An unweighted adjacency matrix graph implementation in Python (allows either directed or undirected representation)

  ## Args

  `labels`
    list of labels for each vertex
  Expand source code

      class AdjacencyMatrixGraph:
          """
          An unweighted adjacency matrix graph implementation in Python
          (allows either directed or undirected representation)
          """
          def __init__(self, labels: list[str]):
              """
              Args:
                  labels: list of labels for each vertex
              """
              self.labels = labels
              self.label_index = { label: index for index, label  in enumerate(labels) }

              node_count = len(self.labels)
              self.array = [[None for i in range(node_count)] for j in range(node_count)]

          def add_edge(self, a_label: str, b_label: str):
              """
              Add an undirected edge between one vertex to another (same as add_edge())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
              """
              self.add_adjacent_vertex(a_label, b_label)

          def add_adjacent_vertex(self, a_label: str, b_label: str):
              """
              Add an undirected edge between one vertex to another (same as add_adjacent_vertex())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
              """
              a = self.label_index[a_label]
              b = self.label_index[b_label]
              self.array[a][b] = True
              self.array[a][a] = True

              self.array[b][a] = True
              self.array[b][b] = True

          def add_directed_edge(self, a_label: str, b_label: str):
              """
              Add a directed edge between one vertex to another (same as add_directed_adjacent_vertex() and add_adjacent_directed_vertex())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
              """
              self.add_adjacent_directed_vertex(a_label, b_label)

          def add_directed_adjacent_vertex(self, a_label: str, b_label: str):
              """
              Add a directed edge between one vertex to another (same as add_adjacent_directed_vertex()  and add_directed_edge())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
              """
              self.add_adjacent_directed_vertex(a_label, b_label)

          def add_adjacent_directed_vertex(self, a_label: str, b_label: str):
              """
              Add a directed edge between one vertex to another (same as add_directed_adjacent_vertex() and add_directed_edge())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
              """
              a = self.label_index[a_label]
              b = self.label_index[b_label]
              self.array[a][b] = True
              self.array[a][a] = True
              self.array[b][b] = True

          def df_traverse(self, start_label: str):
              """
              Perform depth first traversal in an adjacency matrix

              Args:
                  start_label: starting vertex label
              """
              return self._df_rec_traverse(start_label, dict())

          def _df_rec_traverse(self, start_label: str, visited):
              """
              Helper method for depth first recursive traversal
              """
              start_index = self.label_index[start_label]
              visited[start_index] = True
              print(self.labels[start_index])

              for i in range(len(self.array)):
                  if i not in visited and self.array[start_index][i]:
                      self.df_rec_traverse(self.labels[i], visited)

          def bf_traverse(self, start_label: str):
              """
              Perform breadth first traversal in an adjacency matrix

              Args:
                  start_label: starting vertex label
              """
              q = []
              visited={}
              start_index = self.label_index[start_label]
              q.append(start_index)

              while len(q) > 0:
                  current = q.pop(0) # equivalent of dequeue

                  if current not in visited:
                      visited[current] = True
                      print(self.labels[current])

                      for i in range(len(self.array)):
                          if self.array[current][i]:
                              q.append(i)

          def print_graph(self):
              """
              Print the contents of the graph
              """
              print("   |", end="")
              for label in self.labels:
                  print(f"{label:^3}", end=" ")
              print()
              print("----" * (len(self.array) + 1))
              for r, row in enumerate(self.array):
                  label = self.labels[r]
                  print(f"{label:^3}|", end="");
                  for col in row:
                      b = " T " if col else "   "
                      print(b, end=" ")
                  print()

  ### Methods

  `def add_adjacent_directed_vertex(self, a_label: str, b_label: str)`

    Add a directed edge between one vertex to another (same as add_directed_adjacent_vertex() and add_directed_edge())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
  `def add_adjacent_vertex(self, a_label: str, b_label: str)`

    Add an undirected edge between one vertex to another (same as add_adjacent_vertex())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
  `def add_directed_adjacent_vertex(self, a_label: str, b_label: str)`

    Add a directed edge between one vertex to another (same as add_adjacent_directed_vertex() and add_directed_edge())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
  `def add_directed_edge(self, a_label: str, b_label: str)`

    Add a directed edge between one vertex to another (same as add_directed_adjacent_vertex() and add_adjacent_directed_vertex())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
  `def add_edge(self, a_label: str, b_label: str)`

    Add an undirected edge between one vertex to another (same as add_edge())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
  `def bf_traverse(self, start_label: str)`

    Perform breadth first traversal in an adjacency matrix

    ## Args

    `start_label`
      starting vertex label
  `def df_traverse(self, start_label: str)`

    Perform depth first traversal in an adjacency matrix

    ## Args

    `start_label`
      starting vertex label
  `def print_graph(self)`

    Print the contents of the graph

`class AdjacencyMatrixWeightedGraph (labels)`

  A weighted adjacency matrix graph implementation in Python (allows either directed or undirected representation)

  ## Args

  `labels`
    list of labels for each vertex
  Expand source code

      class AdjacencyMatrixWeightedGraph:
          """
          A weighted adjacency matrix graph implementation in Python
          (allows either directed or undirected representation)
          """
          def __init__(self, labels):
              """
              Args:
                  labels: list of labels for each vertex
              """
              self.labels = labels
              self.label_index = { label: index for index, label  in enumerate(labels) }

              node_count = len(self.labels)
              self.array = [[None for i in range(node_count)] for j in range(node_count)]

          def add_edge(self, a_label: str, b_label: str, weight):
              """
              Add an undirected edge between one vertex to another (same as add_edge())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
                  weight: weight of the vertex
              """
              self.add_adjacent_vertex(a_label, b_label, weight)

          def add_adjacent_vertex(self, a_label: str, b_label: str, weight):
              """
              Add an undirected edge between one vertex to another (same as add_edge())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
                  weight: weight of the vertex
              """
              a = self.label_index[a_label]
              b = self.label_index[b_label]

              self.array[a][b] = weight
              self.array[a][a] = 0

              self.array[b][a] = weight
              self.array[b][b] = 0

          def add_directed_edge(self, a_label: str, b_label: str, weight):
              """
              Add a weighted directed edge between one vertex to another (same as add_adjacent_directed_vertex(), add_directed_adjacent_vertex())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
                  weight: weight of the vertex
              """
              self.add_adjacent_directed_vertex(a_label, b_label, weight)

          def add_directed_adjacent_vertex(self, a_label: str, b_label: str, weight):
              """
              Add a weighted directed edge between one vertex to another (same as add_directed_edge(), add_adjacent_directed_vertex())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
                  weight: weight of the vertex
              """
              self.add_adjacent_directed_vertex(a_label, b_label, weight)

          def add_adjacent_directed_vertex(self, a_label: str, b_label: str, weight):
              """
              Add a weighted directed edge between one vertex to another (same as add_directed_edge(), add_directed_adjacent_vertex())

              Args:
                  a_label: starting vertex label
                  b_label: ending vertex label
                  weight: weight of the vertex
              """
              a = self.label_index[a_label]
              b = self.label_index[b_label]

              self.array[a][b] = weight
              self.array[a][a] = 0
              self.array[b][b] = 0

          def print_graph(self):
              """
              Print the contents of the graph.
              """
              print("   |", end="")
              for label in self.labels:
                  print(f"{label:>3}", end=" ")
              print()
              print("----" * (len(self.array) + 1))
              for r, row in enumerate(self.array):
                  label = self.labels[r]
                  print(f"{label:^3}|", end="");
                  for col in row:
                      w = f"{col:3}" if col is not None else "   "
                      print(w, end=" ")
                  print()

  ### Methods

  `def add_adjacent_directed_vertex(self, a_label: str, b_label: str, weight)`

    Add a weighted directed edge between one vertex to another (same as add_directed_edge(), add_directed_adjacent_vertex())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
    `weight`
      weight of the vertex
  `def add_adjacent_vertex(self, a_label: str, b_label: str, weight)`

    Add an undirected edge between one vertex to another (same as add_edge())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
    `weight`
      weight of the vertex
  `def add_directed_adjacent_vertex(self, a_label: str, b_label: str, weight)`

    Add a weighted directed edge between one vertex to another (same as add_directed_edge(), add_adjacent_directed_vertex())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
    `weight`
      weight of the vertex
  `def add_directed_edge(self, a_label: str, b_label: str, weight)`

    Add a weighted directed edge between one vertex to another (same as add_adjacent_directed_vertex(), add_directed_adjacent_vertex())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
    `weight`
      weight of the vertex
  `def add_edge(self, a_label: str, b_label: str, weight)`

    Add an undirected edge between one vertex to another (same as add_edge())

    ## Args

    `a_label`
      starting vertex label
    `b_label`
      ending vertex label
    `weight`
      weight of the vertex
  `def print_graph(self)`

    Print the contents of the graph.

`class Vertex (value)`

  A unweighted adjacency list vertex implementation in Python (allows either directed or undirected representation)

  ## Args

  `value`
    value of the vertex
  Expand source code

      class Vertex:
          pass

  ### Methods

  `def add_adjacent_vertex(self, vertex: type[Vertex])`

    Add an undirected vertex to the adjacency list (same as add_edge()).

    ## Args

    `vertex`
      vertex to add
  `def add_directed_adjacent_vertex(self, vertex: type[Vertex])`

    Add a directed vertex to the adjacency list (same as add_directed_edge()).

    ## Args

    `vertex`
      vertex to add
  `def add_directed_edge(self, vertex: type[Vertex])`

    Add a directed vertex to the adjacency list (same as add_directed_adjacent_vertex()).

    ## Args

    `vertex`
      vertex to add
  `def add_edge(self, vertex: type[Vertex])`

    Add an undirected vertex to the adjacency list (same as add_adjacent_vertex()).

    ## Args

    `vertex`
      vertex to add
  `def bf_traverse(self)`

    Perform breadth first traversal.

  `def bfs(self, end)`

    Recursive breadth first search.

    ## Args

    `end`
      vertex to search for

    Returns: Vertex in the graph None if not found.

  `def df_traverse(self)`

    Perform depth first traversal.

  `def dfs(self, end)`

    Recursive depth first search.

    ## Args

    `end`
      vertex to search for

    Returns: Vertex in the graph None if not found.

  `def dfs_rec(self, current, end, visited=None)`

    helper depth first search recursive function

    Returns: Vertex in the graph None if not found.

`class WeightedVertex (value)`

  A weighted adjacency list vertex implementation in Python (allows either directed or undirected representation)

  ## Args

  `value`
    value of the vertex
  Expand source code

      class WeightedVertex:
          pass

  ### Methods

  `def add_adjacent_vertex(self, vertex: type[WeightedVertex], weight)`

    Add a weighted edge to the adjacency list (same as add_directed_edge()).

    ## Args

    `vertex`
      vertex to add
    `weight`
      weight of the vertex
  `def add_directed_adjacent_vertex(self, vertex: type[WeightedVertex], weight)`

    Add a weighted directed edge to the adjacency list (same as add_directed_edge()).

    ## Args

    `vertex`
      vertex to add
    `weight`
      weight of the vertex
  `def add_directed_edge(self, vertex: type[WeightedVertex], weight)`

    Add a weighted directed edge to the adjacency list (same as add_directed_adjacent_vertex()).

    ## Args

    `vertex`
      vertex to add
    `weight`
      weight of the vertex
  `def add_edge(self, vertex: type[WeightedVertex], weight)`

    Add a weighted directed edge to the adjacency list (same as add_adjacent_vertex()).

    ## Args

    `vertex`
      vertex to add
    `weight`
      weight of the vertex
  `def bf_traverse(self, vertex: type[WeightedVertex])`

    breadth first traversal

    ## Args

    `vertex`
      starting vertex
  `def bfs(self, vertex: type[WeightedVertex], target)`

    breadth first search

    ## Args

    `vertex`
      startering vertex
    `target`
      target value to search for
  `def df_traverse(self, vertex: type[WeightedVertex], visited={})`

    depth first traversal

    ## Args

    `vertex`
      starting vertex
    `visited`
      dictionary of visited vertices
  `def dfs(self, target: type[WeightedVertex])`

    depth first search

    ## Args

    `target`
      target value to search for