Skip to content

Commit

Permalink
More refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy-Grigg committed Nov 28, 2021
1 parent 4d76812 commit d8485d2
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 137 deletions.
77 changes: 8 additions & 69 deletions src/surveying_interview_question.py → src/doe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,17 @@
Calls each separate solution and summarizes results and performance """

import time
import argparse
import sys
import pandas as pd
import pyjion
from itertools import product
from typing import Type

from src.model import (
NetworkXMethod,
DequeMethod,
StackMethod,
IGraphMethod,
RecursiveMethod,
)
from view import GridView
from typing import Type, TYPE_CHECKING

from orchestrator import GridOrchestrator

if TYPE_CHECKING:
from view import GridView

sys.setrecursionlimit(1000000)


Expand Down Expand Up @@ -61,15 +55,15 @@ def run(self) -> pd.DataFrame:
return pd.DataFrame(results)

@staticmethod
def _set_pyjion(pyjion_state):
def _set_pyjion(pyjion_state: bool):
if pyjion_state:
pyjion.enable()
pyjion.config(pgc=False)
else:
pyjion.disable()

@staticmethod
def _run_method(grid: GridView, model_type: Type) -> dict[str, int | float | str]:
def _run_method(grid: "GridView", model_type: Type) -> dict[str, int | float | str]:
print(f"-" * 20)
print(f"Method: {grid}")
sim_run = SimulationRun(grid)
Expand All @@ -88,7 +82,7 @@ def _run_method(grid: GridView, model_type: Type) -> dict[str, int | float | str


class SimulationRun:
def __init__(self, grid: GridView):
def __init__(self, grid: "GridView"):
self.grid = grid
self.wells = None
self._time_taken = None
Expand Down Expand Up @@ -142,58 +136,3 @@ def _print_reservoir_details(self):
reservoir.sort()
reservoir_locations = "; ".join(map(str, reservoir))
print(f"Well size = {len(reservoir)}, locations: {reservoir_locations}")


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Implement the surveying interview question"
)
parser.add_argument(
"--grid_size", type=int, help="Size of the grid to be generated", default=50
)
args = parser.parse_args()

doe = DesignOfExperiments(
# grid_sizes=[10, 50, 100, 500, 1000, 5000, 10000],
grid_sizes=[
10,
50,
100,
500,
],
# location_probabilities=[0.99, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7],
location_probabilities=[0.99, 0.95, 0.9, 0.85, 0.8],
model_types=[
NetworkXMethod,
DequeMethod,
RecursiveMethod,
StackMethod,
IGraphMethod,
],
pyjion_state=[True, False],
)

df = doe.run()

# time_taken_sorted = sorted(time_taken.items(), key=lambda item: item[1])
# for idx, (method_name, duration) in enumerate(time_taken_sorted):
# if idx == 0:
# shortest_time = duration
# shortest_method = method_name
# print(
# f"{1}: "
# f"{shortest_method.ljust(20)}"
# f"Time taken: {shortest_time:.3E} s"
# )
# else:
# print(
# f"{idx + 1}: "
# f"{method_name.ljust(20)}"
# f"Time taken: {duration:.3E} s, "
# f"{duration / shortest_time:.2f} times slower than {shortest_method}"
# )
# df = df.astype(
# {"Grid Size": "int32", "Number of Sites": "int32", "Number of Wells": "int32"}
# )
# df.set_index(["Grid Size", "Probability"], inplace=True)
# df.to_pickle('results/results_all_methods_sparse.pkl')
73 changes: 73 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import argparse

from src.model import (
NetworkXMethod,
DequeMethod,
StackMethod,
IGraphMethod,
RecursiveMethod,
)
from doe import DesignOfExperiments


parser = argparse.ArgumentParser(
description="Implement the surveying interview question"
)
parser.add_argument(
"--grid_size", type=int, help="Size of the grid to be generated", default=50
)
args = parser.parse_args()

doe = DesignOfExperiments(
grid_sizes=[
10,
50,
# 100,
# 500,
# 1000,
# 5000,
# 10000,
],
location_probabilities=[
0.99,
0.95,
0.9,
# 0.85,
# 0.8,
# 0.75,
# 0.7,
],
model_types=[
NetworkXMethod,
DequeMethod,
RecursiveMethod,
StackMethod,
IGraphMethod,
],
pyjion_state=[True, False],
)

df = doe.run()

# time_taken_sorted = sorted(time_taken.items(), key=lambda item: item[1])
# for idx, (method_name, duration) in enumerate(time_taken_sorted):
# if idx == 0:
# shortest_time = duration
# shortest_method = method_name
# print(
# f"{1}: "
# f"{shortest_method.ljust(20)}"
# f"Time taken: {shortest_time:.3E} s"
# )
# else:
# print(
# f"{idx + 1}: "
# f"{method_name.ljust(20)}"
# f"Time taken: {duration:.3E} s, "
# f"{duration / shortest_time:.2f} times slower than {shortest_method}"
# )
# df = df.astype(
# {"Grid Size": "int32", "Number of Sites": "int32", "Number of Wells": "int32"}
# )
# df.set_index(["Grid Size", "Probability"], inplace=True)
# df.to_pickle('results/results_all_methods_sparse.pkl')
150 changes: 82 additions & 68 deletions src/view.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
import colorama
import lxml.etree as ET

from src.model import GridModel
from src.model import GridModel, Cell


class GridView:
TOP_LEFT_CHAR = u"\u250c"
TOP_RIGHT_CHAR = u"\u2510"
TOP_CHAR = u"\u252c"
BOTTOM_LEFT_CHAR = u"\u2514"
BOTTOM_RIGHT_CHAR = u"\u2518"
BOTTOM_CHAR = u"\u2534"
LEFT_CHAR = u"\u251c"
RIGHT_CHAR = u"\u2524"
VERTICAL_CHAR = u"\u2502"
HORIZ_CHAR = u"\u2500"
VERTEX_CHAR = u"\u253c"

def __init__(self, grid: GridModel):
self._grid = grid

def __str__(self) -> str:
return str(self._grid)

@property
def size(self):
return self._grid.size
Expand Down Expand Up @@ -63,72 +54,95 @@ def to_xml(self) -> ET.Element:
def to_ascii_art(self):
"""Render the grid. Relies on a fixed-width font."""

if self._grid.size > 100:
print("Too big to render!")
return

# Use the size of the grid to figure out how much to pad row and column indices by
num_chars_in_label = len(str(self._grid.size))
ascii_table = AsciiGrid(self._grid.cells, self._grid.size).draw()
print(ascii_table)


# Generate column headers
print(
class AsciiGrid:
TOP_LEFT_CHAR = u"\u250c"
TOP_RIGHT_CHAR = u"\u2510"
TOP_CHAR = u"\u252c"
BOTTOM_LEFT_CHAR = u"\u2514"
BOTTOM_RIGHT_CHAR = u"\u2518"
BOTTOM_CHAR = u"\u2534"
LEFT_CHAR = u"\u251c"
RIGHT_CHAR = u"\u2524"
VERTICAL_CHAR = u"\u2502"
HORIZ_CHAR = u"\u2500"
VERTEX_CHAR = u"\u253c"
NEWLINE = "\n"

def __init__(self, grid: set[Cell], grid_size: int, horizontal_lines: bool = False):
self.cells = grid
self.grid_size = grid_size
self.coord_list = list(range(0, self.grid_size)) # Square grid only, so a single list of coords
self.num_chars_in_label = len(str(grid_size - 1))
self.horizontal_lines = horizontal_lines

def draw(self) -> str:
if self.grid_size > 100:
return "Too big to render!"

result = self._top_row()
result += "".join([self._data_row(row_number) for row_number in self.coord_list])
result += self._bottom_line()
return result

def _top_row(self) -> str:
return self._top_line() + self.NEWLINE + self._table_header() + self.NEWLINE

def _top_line(self) -> str:
top_line = (
self.TOP_LEFT_CHAR
+ (self.HORIZ_CHAR * num_chars_in_label + self.TOP_CHAR) * self._grid.size
+ self.HORIZ_CHAR * num_chars_in_label
+ (self.HORIZ_CHAR * self.num_chars_in_label + self.TOP_CHAR) * self.grid_size
+ self.HORIZ_CHAR * self.num_chars_in_label
+ self.TOP_RIGHT_CHAR
)
return top_line

def _table_header(self) -> str:
column_heading_numbers = [
str(y).zfill(num_chars_in_label) for y in list(range(0, self._grid.size))
str(y).zfill(self.num_chars_in_label) for y in list(range(0, self.grid_size))
]
header = self.VERTICAL_CHAR.join(column_heading_numbers) + self.VERTICAL_CHAR
print(
self.VERTICAL_CHAR + " " * num_chars_in_label + self.VERTICAL_CHAR + header
)
column_headings = self.VERTICAL_CHAR.join(column_heading_numbers) + self.VERTICAL_CHAR
header = self.VERTICAL_CHAR + " " * self.num_chars_in_label + self.VERTICAL_CHAR + column_headings
return header

cell_separator = self.VERTEX_CHAR + self.HORIZ_CHAR * num_chars_in_label
def _row_divider(self) -> str:
cell_separator = self.VERTEX_CHAR + self.HORIZ_CHAR * self.num_chars_in_label
row_divider = (
self.LEFT_CHAR
+ self.HORIZ_CHAR * num_chars_in_label
+ cell_separator * self._grid.size
+ self.RIGHT_CHAR
self.LEFT_CHAR
+ self.HORIZ_CHAR * self.num_chars_in_label
+ cell_separator * self.grid_size
+ self.RIGHT_CHAR
)
return row_divider

def _data_row(self, row_number: int) -> str:
if row_number == 0 or self.horizontal_lines:
row = self._row_divider() + self.NEWLINE
else:
row = ""
row += self.VERTICAL_CHAR + str(row_number).zfill(self.num_chars_in_label) + self.VERTICAL_CHAR
for column_number in self.coord_list:
row += self._cell(column_number, row_number) * self.num_chars_in_label + self.VERTICAL_CHAR
return row + self.NEWLINE

def _cell(self, x_coord, y_coord) -> str:
# TODO: Somehow highlight different wells with different colors
marker = (
colorama.Fore.RED + "x" + colorama.Style.RESET_ALL
if (x_coord, y_coord) in self.cells
else " "
)
return marker

print(row_divider)

# Initialize the first row
row = self.VERTICAL_CHAR + str(0).zfill(num_chars_in_label) + self.VERTICAL_CHAR
current_row = 0

# TODO: Make this not rely on a particular creation order
for y_coord in list(range(0, self._grid.size)):
for x_coord in list(range(0, self._grid.size)):
# TODO: Somehow highlight different wells with different colors
marker = (
colorama.Fore.RED + "x" + colorama.Style.RESET_ALL
if (x_coord, y_coord) in self._grid.cells
else " "
)
if y_coord == current_row:
row = row + marker * num_chars_in_label + self.VERTICAL_CHAR
else:
current_row = y_coord
print(row)
print(row_divider)
row = (
self.VERTICAL_CHAR
+ str(y_coord).zfill(num_chars_in_label)
+ self.VERTICAL_CHAR
+ marker * num_chars_in_label
+ self.VERTICAL_CHAR
)
print(row)
print(
def _bottom_line(self) -> str:
return(
self.BOTTOM_LEFT_CHAR
+ (self.HORIZ_CHAR * num_chars_in_label + self.BOTTOM_CHAR)
* self._grid.size
+ self.HORIZ_CHAR * num_chars_in_label
+ (self.HORIZ_CHAR * self.num_chars_in_label + self.BOTTOM_CHAR)
* self.grid_size
+ self.HORIZ_CHAR * self.num_chars_in_label
+ self.BOTTOM_RIGHT_CHAR
)

def __str__(self) -> str:
return str(self._grid)

0 comments on commit d8485d2

Please sign in to comment.