Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 92 additions & 80 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,25 @@
# Configuration for slow tests
# ---------------------------------------------------------------------------------------


def pytest_addoption(parser):
"""
Grabbed from:
https://docs.pytest.org/en/latest/example/simple.html#control-skipping-of-tests-according-to-command-line-option
"""
parser.addoption('--runslow', action='store_true', default=False, help='run slow tests')
parser.addoption("--runslow", action="store_true", default=False, help="run slow tests")


def pytest_collection_modifyitems(config, items):
if config.getoption('--runslow'):
if config.getoption("--runslow"):
# --runslow given in cli: do not skip slow tests
return
skip_slow = pytest.mark.skip(reason='need --runslow option to run')
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
for item in items:
if 'slow' in item.keywords:
if "slow" in item.keywords:
item.add_marker(skip_slow)


# ---------------------------------------------------------------------------------------
# Graph objects shared between tests
# ---------------------------------------------------------------------------------------
Expand All @@ -34,60 +36,66 @@ def pytest_collection_modifyitems(config, items):
# Graph 1: Simple graph. Required edges only. CPP == RPP
# -------------------------------------------------------------------------------------

@pytest.fixture(scope='session', autouse=True)
def GRAPH_1():
return nx.MultiGraph([
('a', 'b', {'id': 1, 'distance': 5}),
('a', 'c', {'id': 2, 'distance': 20}),
('b', 'c', {'id': 3, 'distance': 10}),
('c', 'd', {'id': 4, 'distance': 3}),
('d', 'b', {'id': 5, 'distance': 2})
])


@pytest.fixture(scope='session', autouse=True)
@pytest.fixture(scope="session", autouse=True)
def GRAPH_1():
return nx.MultiGraph(
[
("a", "b", {"id": 1, "distance": 5}),
("a", "c", {"id": 2, "distance": 20}),
("b", "c", {"id": 3, "distance": 10}),
("c", "d", {"id": 4, "distance": 3}),
("d", "b", {"id": 5, "distance": 2}),
]
)


@pytest.fixture(scope="session", autouse=True)
def GRAPH_1_EDGELIST_DF_W_ID():
return pd.DataFrame({
'node1': ['a', 'a', 'b', 'c', 'd'],
'node2': ['b', 'c', 'c', 'd', 'b'],
'distance': [5, 20, 10, 3, 2],
'id': [1, 2, 3, 4, 5]
}, columns=['node1', 'node2', 'distance', 'id'])


@pytest.fixture(scope='function', autouse=True, )
return pd.DataFrame(
{
"node1": ["a", "a", "b", "c", "d"],
"node2": ["b", "c", "c", "d", "b"],
"distance": [5, 20, 10, 3, 2],
"id": [1, 2, 3, 4, 5],
},
columns=["node1", "node2", "distance", "id"],
)


@pytest.fixture(
scope="function",
autouse=True,
)
def GRAPH_1_EDGELIST_DF(GRAPH_1_EDGELIST_DF_W_ID):
return GRAPH_1_EDGELIST_DF_W_ID.drop('id', axis=1)
return GRAPH_1_EDGELIST_DF_W_ID.drop("id", axis=1)


@pytest.fixture(scope='function', autouse=True)
@pytest.fixture(scope="function", autouse=True)
def GRAPH_1_EDGELIST_CSV(GRAPH_1_EDGELIST_DF):
return create_mock_csv_from_dataframe(GRAPH_1_EDGELIST_DF)


@pytest.fixture(scope='function', autouse=True)
@pytest.fixture(scope="function", autouse=True)
def GRAPH_1_EDGELIST_W_ID_CSV(GRAPH_1_EDGELIST_DF_W_ID):
return create_mock_csv_from_dataframe(GRAPH_1_EDGELIST_DF_W_ID)


@pytest.fixture(scope='session', autouse=True)
@pytest.fixture(scope="session", autouse=True)
def GRAPH_1_NODE_ATTRIBUTES():
return pd.DataFrame({
'id': ['a', 'b', 'c', 'd'],
'attr_fruit': ['apple', 'banana', 'cherry', 'durian']
})
return pd.DataFrame({"id": ["a", "b", "c", "d"], "attr_fruit": ["apple", "banana", "cherry", "durian"]})


@pytest.fixture(scope='session', autouse=True)
@pytest.fixture(scope="session", autouse=True)
def GRAPH_1_CIRCUIT_CPP():
return [
('a', 'b', 0, {'distance': 5, 'id': 0}),
('b', 'd', 0, {'distance': 2, 'augmented': True, 'id': 4}),
('d', 'c', 0, {'distance': 3, 'augmented': True, 'id': 3}),
('c', 'b', 0, {'distance': 10, 'id': 2}),
('b', 'd', 0, {'distance': 2, 'id': 4}),
('d', 'c', 0, {'distance': 3, 'id': 3}),
('c', 'a', 0, {'distance': 20, 'id': 1})
("a", "b", 0, {"distance": 5, "id": 0}),
("b", "d", 0, {"distance": 2, "augmented": True, "id": 4}),
("d", "c", 0, {"distance": 3, "augmented": True, "id": 3}),
("c", "b", 0, {"distance": 10, "id": 2}),
("b", "d", 0, {"distance": 2, "id": 4}),
("d", "c", 0, {"distance": 3, "id": 3}),
("c", "a", 0, {"distance": 20, "id": 1}),
]


Expand All @@ -96,35 +104,37 @@ def GRAPH_1_CIRCUIT_CPP():
# -------------------------------------------------------------------------------------


@pytest.fixture(scope='session', autouse=True)
@pytest.fixture(scope="session", autouse=True)
def GRAPH_2():
return nx.MultiGraph([
('a', 'b', {'distance': 20, 'required': 1}),
('a', 'c', {'distance': 25, 'required': 1}),
('a', 'd', {'distance': 30, 'required': 1}),
('a', 'e', {'distance': 35, 'required': 1}),
('b', 'c', {'distance': 2, 'required': 0}),
('c', 'd', {'distance': 3, 'required': 0}),
('d', 'e', {'distance': 4, 'required': 0}),
('e', 'b', {'distance': 6, 'required': 0})
])


@pytest.fixture(scope='session', autouse=True)
return nx.MultiGraph(
[
("a", "b", {"distance": 20, "required": 1}),
("a", "c", {"distance": 25, "required": 1}),
("a", "d", {"distance": 30, "required": 1}),
("a", "e", {"distance": 35, "required": 1}),
("b", "c", {"distance": 2, "required": 0}),
("c", "d", {"distance": 3, "required": 0}),
("d", "e", {"distance": 4, "required": 0}),
("e", "b", {"distance": 6, "required": 0}),
]
)


@pytest.fixture(scope="session", autouse=True)
def GRAPH_2_EDGELIST_CSV(GRAPH_2):
edgelist = nx.to_pandas_edgelist(GRAPH_2, source='_node1', target='_node2')
edgelist = nx.to_pandas_edgelist(GRAPH_2, source="_node1", target="_node2")
return create_mock_csv_from_dataframe(edgelist)


@pytest.fixture(scope='session', autouse=True)
@pytest.fixture(scope="session", autouse=True)
def GRAPH_2_CIRCUIT_RPP():
return [
('a', 'c', 0, {'distance': 25, 'id': 4, 'required': 1}),
('c', 'b', 0, {'distance': 2, 'id': 6, 'augmented': True, 'required': 0}),
('b', 'a', 0, {'distance': 20, 'id': 3, 'required': 1}),
('a', 'e', 0, {'distance': 35, 'id': 5, 'required': 1}),
('e', 'd', 0, {'distance': 4, 'id': 2, 'augmented': True, 'required': 0}),
('d', 'a', 0, {'distance': 30, 'id': 0, 'required': 1})
("a", "c", 0, {"distance": 25, "id": 4, "required": 1}),
("c", "b", 0, {"distance": 2, "id": 6, "augmented": True, "required": 0}),
("b", "a", 0, {"distance": 20, "id": 3, "required": 1}),
("a", "e", 0, {"distance": 35, "id": 5, "required": 1}),
("e", "d", 0, {"distance": 4, "id": 2, "augmented": True, "required": 0}),
("d", "a", 0, {"distance": 30, "id": 0, "required": 1}),
]


Expand All @@ -133,23 +143,25 @@ def GRAPH_2_CIRCUIT_RPP():
# -------------------------------------------------------------------------------------


@pytest.fixture(scope='session', autouse=True)
@pytest.fixture(scope="session", autouse=True)
def GRAPH_3():
return nx.MultiGraph([
('a', 'b', {'distance': 20, 'required': 1}),
('a', 'c', {'distance': 25, 'required': 1}),
('a', 'd', {'distance': 30, 'required': 1}),
('a', 'e', {'distance': 35, 'required': 1}),
('b', 'c', {'distance': 2, 'required': 0}),
('c', 'd', {'distance': 3, 'required': 0}),
('d', 'e', {'distance': 4, 'required': 0}),
('e', 'b', {'distance': 6, 'required': 0}),
('b', 'f', {'distance': 7, 'required': 0}),
('f', 'g', {'distance': 8, 'required': 1})
])


@pytest.fixture(scope='session', autouse=True)
return nx.MultiGraph(
[
("a", "b", {"distance": 20, "required": 1}),
("a", "c", {"distance": 25, "required": 1}),
("a", "d", {"distance": 30, "required": 1}),
("a", "e", {"distance": 35, "required": 1}),
("b", "c", {"distance": 2, "required": 0}),
("c", "d", {"distance": 3, "required": 0}),
("d", "e", {"distance": 4, "required": 0}),
("e", "b", {"distance": 6, "required": 0}),
("b", "f", {"distance": 7, "required": 0}),
("f", "g", {"distance": 8, "required": 1}),
]
)


@pytest.fixture(scope="session", autouse=True)
def GRAPH_3_EDGELIST_CSV(GRAPH_3):
edgelist = nx.to_pandas_edgelist(GRAPH_3, source='_node1', target='_node2')
return create_mock_csv_from_dataframe(edgelist)
edgelist = nx.to_pandas_edgelist(GRAPH_3, source="_node1", target="_node2")
return create_mock_csv_from_dataframe(edgelist)
90 changes: 48 additions & 42 deletions postman_problems/examples/seven_bridges/cpp_seven_bridges.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,68 +36,74 @@ def main():
# PARAMS / DATA ---------------------------------------------------------------------

# inputs
EDGELIST = pkg_resources.resource_filename('postman_problems', 'examples/seven_bridges/edgelist_seven_bridges.csv')
START_NODE = 'D'
EDGELIST = pkg_resources.resource_filename("postman_problems", "examples/seven_bridges/edgelist_seven_bridges.csv")
START_NODE = "D"

# outputs
PNG_PATH = pkg_resources.resource_filename('postman_problems', 'examples/seven_bridges/output/png/')
CPP_VIZ_FILENAME = pkg_resources.resource_filename('postman_problems', 'examples/seven_bridges/output/cpp_graph')
CPP_BASE_VIZ_FILENAME = pkg_resources.resource_filename('postman_problems',
'examples/seven_bridges/output/base_cpp_graph')
CPP_GIF_FILENAME = pkg_resources.resource_filename('postman_problems',
'examples/seven_bridges/output/cpp_graph.gif')
PNG_PATH = pkg_resources.resource_filename("postman_problems", "examples/seven_bridges/output/png/")
CPP_VIZ_FILENAME = pkg_resources.resource_filename("postman_problems", "examples/seven_bridges/output/cpp_graph")
CPP_BASE_VIZ_FILENAME = pkg_resources.resource_filename(
"postman_problems", "examples/seven_bridges/output/base_cpp_graph"
)
CPP_GIF_FILENAME = pkg_resources.resource_filename(
"postman_problems", "examples/seven_bridges/output/cpp_graph.gif"
)

# setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# SOLVE CPP -------------------------------------------------------------------------

logger.info('Solve CPP')
logger.info("Solve CPP")
circuit, graph = cpp(edgelist_filename=EDGELIST, start_node=START_NODE)

logger.info('Print the CPP solution:')
logger.info("Print the CPP solution:")
for e in circuit:
logger.info(e)

logger.info('Solution summary stats:')
logger.info("Solution summary stats:")
for k, v in calculate_postman_solution_stats(circuit).items():
logger.info(str(k) + ' : ' + str(v))
logger.info(str(k) + " : " + str(v))

# VIZ -------------------------------------------------------------------------------

try:
from postman_problems.viz import plot_circuit_graphviz, make_circuit_images, make_circuit_video

logger.info('Creating single SVG of base graph')
plot_circuit_graphviz(circuit=circuit,
graph=graph,
filename=CPP_BASE_VIZ_FILENAME,
edge_label_attr='distance',
format='svg',
engine='circo',
graph_attr={'label': 'Base Graph: Distances', 'labelloc': 't'})

logger.info('Creating single SVG of CPP solution')
plot_circuit_graphviz(circuit=circuit,
graph=graph,
filename=CPP_VIZ_FILENAME,
format='svg',
engine='circo',
graph_attr={'label': 'Base Graph: Chinese Postman Solution', 'labelloc': 't'})

logger.info('Creating PNG files for GIF')
make_circuit_images(circuit=circuit,
graph=graph,
outfile_dir=PNG_PATH,
format='png',
engine='circo',
graph_attr={'label': 'Base Graph: Chinese Postman Solution', 'labelloc': 't'})

logger.info('Creating GIF')
video_message = make_circuit_video(infile_dir_images=PNG_PATH,
outfile_movie=CPP_GIF_FILENAME,
fps=0.5)
logger.info("Creating single SVG of base graph")
plot_circuit_graphviz(
circuit=circuit,
graph=graph,
filename=CPP_BASE_VIZ_FILENAME,
edge_label_attr="distance",
format="svg",
engine="circo",
graph_attr={"label": "Base Graph: Distances", "labelloc": "t"},
)

logger.info("Creating single SVG of CPP solution")
plot_circuit_graphviz(
circuit=circuit,
graph=graph,
filename=CPP_VIZ_FILENAME,
format="svg",
engine="circo",
graph_attr={"label": "Base Graph: Chinese Postman Solution", "labelloc": "t"},
)

logger.info("Creating PNG files for GIF")
make_circuit_images(
circuit=circuit,
graph=graph,
outfile_dir=PNG_PATH,
format="png",
engine="circo",
graph_attr={"label": "Base Graph: Chinese Postman Solution", "labelloc": "t"},
)

logger.info("Creating GIF")
video_message = make_circuit_video(infile_dir_images=PNG_PATH, outfile_movie=CPP_GIF_FILENAME, fps=0.5)

logger.info(video_message)
logger.info("and that's a wrap, checkout the output!")
Expand All @@ -107,5 +113,5 @@ def main():
print("Sorry, looks like you don't have all the needed visualization dependencies.")


if __name__ == '__main__':
if __name__ == "__main__":
main()
Loading