Browse Source

add graph coloring logic

highing666 3 years ago
parent
commit
a26e1a45c0

+ 11 - 10
app/api/routers/algorithms.py

@@ -1,4 +1,5 @@
-from fastapi import APIRouter, Query
+from fastapi import APIRouter
+from loguru import logger
 
 from app.controllers.algorithms.graph_coloring import get_graph_coloring
 from app.models.domain.algorithms import GraphColoringRequest, GraphColoringResponse
@@ -7,14 +8,14 @@ router = APIRouter()
 
 
 @router.post('/graph-coloring', response_model=GraphColoringResponse)
-async def get_graph_coloring_result(graph_info: GraphColoringRequest):
-    black, white, random = await get_graph_coloring(
-        graph_info.vertexes,
-        graph_info.edges
-    )
+async def get_graph_coloring_result(graph: GraphColoringRequest):
+    is_solvable, colored = await get_graph_coloring(graph.graph)
 
-    return {
-        'black': black,
-        'white': white,
-        'random': random
+    solution = {
+        'is_solvable': is_solvable,
+        'colored': colored
     }
+
+    logger.debug(solution)
+
+    return solution

+ 73 - 3
app/controllers/algorithms/graph_coloring.py

@@ -1,7 +1,77 @@
-from typing import List, Tuple
+import random
+from queue import Queue
+from typing import Dict, List, Optional, Tuple
 
 from loguru import logger
+from pydantic import BaseModel
 
 
-async def get_graph_coloring(vertexes: List[str], edges: List[List[str]]) -> Tuple[List[str], List[str], List[str]]:
-    pass
+class Vertex(BaseModel):
+    id: str
+    color: Optional[int]
+    edges: Optional[set]
+
+
+class ColoringProblemBFSSolution:
+
+    def __init__(self, vertexes: List[Vertex]):
+        self._vertexes = vertexes
+        self._is_solvable = False
+
+    def bfs(self, m=2):
+        n = len(self._vertexes)
+        visited = [False for _ in range(n + 1)]
+        max_color_count = 1
+
+        for i in range(1, n + 1):
+            if not visited[i]:
+                visited[i] = True
+                q = Queue()
+                q.put(i)
+
+                while not q.empty():
+                    top = q.get()
+
+                    for j in self._vertexes[top].edges:
+                        if self._vertexes[top].color == self._vertexes[j].color:
+                            self._vertexes[j].color += 1
+
+                        max_color_count = max(max_color_count, max(self._vertexes[top].color, self._vertexes[j].color))
+                        if max_color_count > m:
+                            return False
+
+                        if not visited[j]:
+                            visited[j] = True
+                            q.put(j)
+
+        self._is_solvable = True
+
+        return True
+
+    def get_colored(self) -> Dict[str, int]:
+        colored = dict()
+        if self._is_solvable:
+            for v in self._vertexes:
+                colored.update({v.id: v.color})
+        else:
+            for v in self._vertexes:
+                colored.update({v.id: random.choice([0, 1])})
+
+        return colored
+
+
+def reformat(graph: Dict[str, List]) -> List[Vertex]:
+    vertexes = []
+    for v, edges in graph.items():
+        vertexes.append(Vertex(id=v, color=0, edges=set(edges)))
+
+    return vertexes
+
+
+@logger.catch()
+async def get_graph_coloring(graph: Dict[str, List]) -> Tuple[bool, Dict[str, int]]:
+    vertexes = reformat(graph)
+    solution = ColoringProblemBFSSolution(vertexes)
+    is_solvable = solution.bfs()
+
+    return is_solvable, solution.get_colored()

+ 4 - 6
app/models/domain/algorithms.py

@@ -1,14 +1,12 @@
-from typing import List, Optional
+from typing import Dict, List
 
 from pydantic import BaseModel
 
 
 class GraphColoringResponse(BaseModel):
-    black: List[str]
-    white: List[str]
-    random: List[str]
+    is_solvable: bool
+    colored: Dict[str, int]
 
 
 class GraphColoringRequest(BaseModel):
-    vertexes: List[str]
-    edges: List[List[str]]
+    graph: Dict[str, List]