Skip to content

Commit

Permalink
init ci
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgiving committed Oct 1, 2023
1 parent 5a32d55 commit 7419b5d
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 36 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI

on: [push]

jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.9"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_qa.txt
- name: Test clique solver
run: |
source scripts/bootstrap.sh
pytest -v -m clique
- name: Test coloring solver
run: |
source scripts/bootstrap.sh
pytest -v -m coloring
2 changes: 1 addition & 1 deletion benchmark_coloring.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class CommonParams:
result_dict[ResultColumns.INSTANCE].append(instance)
result_dict[ResultColumns.TIME].append(round(total_coloring_time, 2))
result_dict[ResultColumns.COLORS].append(best_result.num_colors)
result_dict[ResultColumns.RESULT].append(best_result.color_vertexes)
result_dict[ResultColumns.RESULT].append(best_result.color_vertices)

if params.save_coloring:
params.save_coloring_path.mkdir(parents=True, exist_ok=True)
Expand Down
10 changes: 5 additions & 5 deletions heurograph/clique/greedy_randomized_clique.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def nx_clique(graph: Graph) -> list[int]:
return best_clique


def _get_clique(start_vertex: int, graph: Graph) -> list[int]:
def find_clique(start_vertex: int, graph: Graph) -> list[int]:
clique = [start_vertex]
vertices_candidates = graph.neighbors(start_vertex)
np.random.shuffle(vertices_candidates)
Expand All @@ -35,25 +35,25 @@ def _get_clique(start_vertex: int, graph: Graph) -> list[int]:

def greedy_randomized_clique(graph: Graph, iterations: int = 10) -> list[int]:
best_clique = []
vertices = graph.vertexes
vertices = graph.vertices

for _ in range(iterations):
clique = []
random_vertex = random.choice(vertices)
clique = _get_clique(random_vertex, graph)
clique = find_clique(random_vertex, graph)
if len(clique) > len(best_clique):
best_clique = clique
return best_clique


def greedy_randomized_mp_clique(graph: Graph, iterations: int = 10, num_proc: int = -1) -> list[int]:
best_clique = []
vertices = graph.vertexes
vertices = graph.vertices

random_vertices = np.random.choice(vertices, iterations)
num_process = num_proc if num_proc > 1 else cpu_count()

partial_get_clique = partial(_get_clique, graph=graph)
partial_get_clique = partial(find_clique, graph=graph)
with Pool(num_process) as pool:
cliques = pool.map(partial_get_clique, random_vertices)
best_clique = max(cliques, key=len)
Expand Down
24 changes: 24 additions & 0 deletions heurograph/clique/test_clique.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest

from heurograph import Graph
from heurograph.clique import find_clique


def _validate_clique(clique: list[int], graph: Graph) -> bool:
for clique_vertex in clique:
clique_copy = clique.copy()
clique_copy.remove(clique_vertex)
for _clique_vertex in clique_copy:
if _clique_vertex not in graph.neighbors(clique_vertex):
return False
return True


@pytest.mark.clique
def test_find_clique() -> None:
graph = Graph()
graph.make_complete()

clique = find_clique(graph.vertices[0], graph)
if not _validate_clique(clique, graph):
raise ValueError('Solver returns not clique')
1 change: 1 addition & 0 deletions heurograph/coloring/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from heurograph.coloring.coloring_result import ColoringResult
from heurograph.coloring.greedy_coloring import (
color_graph_greedy, color_graph_greedy_randomized_sorted,
color_graph_greedy_sorted, color_graph_greedy_sorted_shuffled)
18 changes: 9 additions & 9 deletions heurograph/coloring/coloring_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@
class ColoringResult:
def __init__(self, vertex_color: dict[int, int]) -> None:
self._vertex_color = vertex_color
self._color_vertexes = None
self._color_vertices = None

def _prepare_result(self) -> dict[int, list[int]]:
color_vertexes = defaultdict(list)
color_vertices = defaultdict(list)
for vertex in self._vertex_color:
color = self._vertex_color[vertex]
color_vertexes[color].append(vertex)
return dict(color_vertexes)
color_vertices[color].append(vertex)
return dict(color_vertices)

@property
def color_vertexes(self) -> dict[int, list[int]]:
if not self._color_vertexes:
self._color_vertexes = self._prepare_result()
return self._color_vertexes
def color_vertices(self) -> dict[int, list[int]]:
if not self._color_vertices:
self._color_vertices = self._prepare_result()
return self._color_vertices

@property
def num_colors(self) -> int:
return len(self.color_vertexes)
return len(self.color_vertices)

@property
def ordered_colors(self) -> list[int]:
Expand Down
24 changes: 12 additions & 12 deletions heurograph/coloring/greedy_coloring.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ def _get_available_color(neighbor_colors: list[int]) -> int:


def color_graph_greedy(graph: Graph) -> ColoringResult:
vertex_colors = dict(zip(graph.vertexes, [None] * graph.num_vertex))
vertex_colors = dict(zip(graph.vertices, [None] * graph.num_vertex))

for vertex in graph.vertexes:
for vertex in graph.vertices:
if vertex_colors[vertex]:
continue

Expand All @@ -28,10 +28,10 @@ def color_graph_greedy(graph: Graph) -> ColoringResult:


def color_graph_greedy_sorted(graph: Graph) -> ColoringResult:
vertex_colors = dict(zip(graph.vertexes, [None] * graph.num_vertex))
sorted_vertexes = graph.sort()
vertex_colors = dict(zip(graph.vertices, [None] * graph.num_vertex))
sorted_vertices = graph.sort()

for vertex in sorted_vertexes:
for vertex in sorted_vertices:
if vertex_colors[vertex]:
continue

Expand All @@ -43,12 +43,12 @@ def color_graph_greedy_sorted(graph: Graph) -> ColoringResult:


def color_graph_greedy_randomized_sorted(graph: Graph) -> ColoringResult:
vertex_colors = dict(zip(graph.vertexes, [None] * graph.num_vertex))
vertex_colors = dict(zip(graph.vertices, [None] * graph.num_vertex))

vertexes_probabilities = [len(graph._data[vertex]) / graph.num_edges / 2 for vertex in graph.vertexes]
randomized_vertexes = np.random.choice(graph.vertexes, graph.num_vertex, p=vertexes_probabilities, replace=False)
vertices_probabilities = [len(graph._data[vertex]) / graph.num_edges / 2 for vertex in graph.vertices]
randomized_vertices = np.random.choice(graph.vertices, graph.num_vertex, p=vertices_probabilities, replace=False)

for vertex in randomized_vertexes:
for vertex in randomized_vertices:

if vertex_colors[vertex]:
continue
Expand All @@ -61,10 +61,10 @@ def color_graph_greedy_randomized_sorted(graph: Graph) -> ColoringResult:


def color_graph_greedy_sorted_shuffled(graph: Graph) -> ColoringResult:
vertex_colors = dict(zip(graph.vertexes, [None] * graph.num_vertex))
sorted_vertexes = graph.sort_shuffle()
vertex_colors = dict(zip(graph.vertices, [None] * graph.num_vertex))
sorted_vertices = graph.sort_shuffle()

for vertex in sorted_vertexes:
for vertex in sorted_vertices:
if vertex_colors[vertex]:
continue

Expand Down
35 changes: 35 additions & 0 deletions heurograph/coloring/test_coloring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import Callable

import pytest

from heurograph import Graph
from heurograph.coloring import (ColoringResult, color_graph_greedy,
color_graph_greedy_randomized_sorted,
color_graph_greedy_sorted,
color_graph_greedy_sorted_shuffled)


def _validate_coloring(coloring: list[int], graph: Graph) -> bool:
for vertex_1 in graph.vertices:
for vertex_2 in graph.neighbors(vertex_1):
if coloring[vertex_1] == coloring[vertex_2]:
return False
return True


testing_functions = [
color_graph_greedy,
color_graph_greedy_randomized_sorted,
color_graph_greedy_sorted,
color_graph_greedy_sorted_shuffled
]

@pytest.mark.clique
@pytest.mark.parametrize('function', testing_functions)
def test_coloring(function: Callable) -> None:
graph = Graph()
graph.make_complete()

coloring_result: ColoringResult = function(graph)
if not _validate_coloring(coloring_result.ordered_colors, graph):
raise ValueError('Solver returns not correct coloring')
20 changes: 12 additions & 8 deletions heurograph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ def neighbors(self, vertex: int) -> list[int]:
return self._data[vertex]

@property
def vertexes(self) -> list[int]:
def vertices(self) -> list[int]:
return [int(vertex) for vertex in self._data]

@property
def num_vertex(self) -> int:
return len(self.vertexes)
return len(self.vertices)

@property
def num_edges(self) -> int:
num_edges = 0
for vertex in self.vertexes:
for vertex in self.vertices:
num_edges += len(self._data[vertex])
return num_edges // 2 # to remove duplicates

Expand All @@ -59,6 +59,10 @@ def as_dict(self) -> dict[int, int]:

def as_nxgraph(self) -> nx.Graph:
return nx.from_dict_of_lists(self.as_dict())

def make_complete(self, num_vertices: int = 100) -> None:
nx_graph = nx.complete_graph(num_vertices)
self._data = nx.to_dict_of_lists(nx_graph)

def visualize(self, path: Path = Path('graph.png'),
with_labels: bool = True,
Expand Down Expand Up @@ -88,7 +92,7 @@ def sort_shuffle(self, reverse: bool = True) -> list[int]:

sorted_edges = self.sort()

permuted_vertexes = []
permuted_vertices = []

temp = []
current_edges = 0
Expand All @@ -100,9 +104,9 @@ def sort_shuffle(self, reverse: bool = True) -> list[int]:
if edges_dict[vertex] == current_edges:
temp.append(vertex)
else:
shuffled_vertexes = np.random.permutation(temp)
permuted_vertexes.extend(shuffled_vertexes)
shuffled_vertices = np.random.permutation(temp)
permuted_vertices.extend(shuffled_vertices)
temp = [vertex]
current_edges = edges_dict[vertex]
permuted_vertexes.extend(temp)
return permuted_vertexes
permuted_vertices.extend(temp)
return permuted_vertices
4 changes: 4 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pytest]
markers =
clique: Test for clique solver
coloring: Test for coloring solver
3 changes: 2 additions & 1 deletion requirements_qa.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
isort==5.12.0
isort==5.12.0
pytest==7.4.2
2 changes: 2 additions & 0 deletions scripts/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export PYTHONPATH=${PYTHONPATH}:$(pwd)
export PYTHONUNBUFFERED=true

0 comments on commit 7419b5d

Please sign in to comment.