diff --git a/__init__.py b/__init__.py index 925765359b3e7057b8cf38a1d5aa35ee1e943f7d..b902ffbb29853b0461aff1d284260c077ce86295 100644 --- a/__init__.py +++ b/__init__.py @@ -15,4 +15,5 @@ __all__ = [ 'WeightedGraph', 'WeightedEdge', 'WeightedNode', 'DirectedWeightedEdge', 'DirectedWeightedNode', 'DirectedWeightedGraph', + 'NetworkFlowEdge', 'NetworkFlowNode', 'NetworkFlowGraph', ] diff --git a/resources/__init__.py b/resources/__init__.py index a56c5a64b7e6cd4f0f1c5417ca807e0ffd3dbc35..3785cc43f65e253778bead389778980ce6e028f1 100644 --- a/resources/__init__.py +++ b/resources/__init__.py @@ -15,4 +15,5 @@ __all__ = [ 'WeightedEdge', 'WeightedNode', 'WeightedGraph', 'DirectedWeightedEdge', 'DirectedWeightedNode', 'DirectedWeightedGraph', + 'NetworkFlowEdge', 'NetworkFlowNode', 'NetworkFlowGraph', ] diff --git a/resources/graphs/__init__.py b/resources/graphs/__init__.py index c15d5351311cc9c8a975c42f40839f8590c03f16..d757fe404644321b8754a9084fbaabc7c6efa7b0 100644 --- a/resources/graphs/__init__.py +++ b/resources/graphs/__init__.py @@ -6,6 +6,7 @@ from .basic_graph import * from .directed_graph import * from .directed_weighted_graph import * +from .network_flow_graph import * from .state_machine import * from .weighted_graph import * @@ -19,4 +20,5 @@ __all__ = [ 'WeightedEdge', 'WeightedNode', 'WeightedGraph', 'DirectedWeightedEdge', 'DirectedWeightedNode', 'DirectedWeightedGraph', + 'NetworkFlowEdge', 'NetworkFlowNode', 'NetworkFlowGraph', ] diff --git a/resources/graphs/network_flow_graph/__init__.py b/resources/graphs/network_flow_graph/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f0b274f0a52e79aef21d37e0026438d1086d7d11 --- /dev/null +++ b/resources/graphs/network_flow_graph/__init__.py @@ -0,0 +1,13 @@ +""" +"Network Flow Graph" folder importing definitions. +""" + +# Import files/values we want to be available to other folders. +from .components import NetworkFlowEdge, NetworkFlowNode +from .graph import NetworkFlowGraph + + +# Define imports when using the * flag on this folder. +__all__ = [ + 'NetworkFlowEdge', 'NetworkFlowNode', 'NetworkFlowGraph', +] diff --git a/resources/graphs/network_flow_graph/components.py b/resources/graphs/network_flow_graph/components.py new file mode 100644 index 0000000000000000000000000000000000000000..e171dbdde75ce808c7bf64cac212f6d69333deef --- /dev/null +++ b/resources/graphs/network_flow_graph/components.py @@ -0,0 +1,57 @@ +""" +Date: 12-03-19 +Class: CS5310 +Assignment: Graph Library +Author: Brandon Rodriguez + + +Edge and Node classes for a "network flow graph" (Has edge weights and edge directions). +Essentially the "vertex" and "vertex connection" classes in a Graph data structure. + +These classes are combined into one single file to avoid circular import dependencies. +""" + +# System Imports. + +# User Class Imports. +from ..directed_weighted_graph.components import DirectedWeightedEdge, DirectedWeightedNode + + +#region Logging Initialization + +# Since this is a library, we specifically only modify logging if the library is being run alone. +try: + # First, try to import the variable specific to our library logging. + from resources.logging import graph_library_logger + + # It worked, so we know the project is being run stand alone, probably as a unittest. + # Proceed to configure logging. + from resources.logging import get_logger as init_logging + logger = init_logging(__name__) +except (ImportError, ModuleNotFoundError): + # Above import failed. Project is being run as a library. + # Just import existing logger and do not modify. + import logging as init_logging + logger = init_logging.getLogger('graph_library') + +#endregion Logging Initialization + + +class NetworkFlowEdge(DirectedWeightedEdge): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Define expected class types (should all be of "Network Flow" type). + # This is necessary for inheritance, or else child classes will only have access to parent functions. + self._edge_type = NetworkFlowEdge + self._node_type = NetworkFlowNode + + +class NetworkFlowNode(DirectedWeightedNode): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Define expected class types (should all be of "Network Flow" type). + # This is necessary for inheritance, or else child classes will only have access to parent functions. + self._edge_type = NetworkFlowEdge + self._node_type = NetworkFlowNode diff --git a/resources/graphs/network_flow_graph/graph.py b/resources/graphs/network_flow_graph/graph.py new file mode 100644 index 0000000000000000000000000000000000000000..19797ea8dbd0454b17566242c68f9927de769ed2 --- /dev/null +++ b/resources/graphs/network_flow_graph/graph.py @@ -0,0 +1,89 @@ +""" +Date: 12-03-19 +Class: CS5310 +Assignment: Graph Library +Author: Brandon Rodriguez + + +Graph class for a "network flow graph" (Has edge weights and edge directions). +Parent structure containing various Nodes and Edges. +""" + +# System Imports. + +# User Class Imports. +from .components import NetworkFlowEdge, NetworkFlowNode +from ..directed_weighted_graph.graph import ( + DirectedWeightedGraph, + DirectedWeightedGraphDisplay, + DirectedWeightedGraphEdges, + DirectedWeightedGraphNodes, +) + +#region Logging Initialization + +# Since this is a library, we specifically only modify logging if the library is being run alone. +try: + # First, try to import the variable specific to our library logging. + from resources.logging import graph_library_logger + + # It worked, so we know the project is being run stand alone, probably as a unittest. + # Proceed to configure logging. + from resources.logging import get_logger as init_logging + logger = init_logging(__name__) +except (ImportError, ModuleNotFoundError): + # Above import failed. Project is being run as a library. + # Just import existing logger and do not modify. + import logging as init_logging + logger = init_logging.getLogger('graph_library') + +#endregion Logging Initialization + + +class NetworkFlowGraph(DirectedWeightedGraph): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Define expected class types (should all be of "Directed, Weighted" type). + # This is necessary for inheritance, or else child classes will only have access to parent functions. + self._edge_type = NetworkFlowEdge + self._graph_type = NetworkFlowGraph + self._node_type = NetworkFlowNode + + # Get associated child classes. + self.display = NetworkFlowGraphDisplay(self) + self.edges = NetworkFlowGraphEdges(self) + self.nodes = NetworkFlowGraphNodes(self) + + +class NetworkFlowGraphDisplay(DirectedWeightedGraphDisplay): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, *kwargs) + + if not isinstance(parent, NetworkFlowGraph): + raise TypeError('Expected parent of type NetworkFlowGraph.') + + # Get calling parent. + self._parent = parent + + +class NetworkFlowGraphEdges(DirectedWeightedGraphEdges): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, *kwargs) + + if not isinstance(parent, NetworkFlowGraph): + raise TypeError('Expected parent of type NetworkFlowGraph.') + + # Get calling parent. + self._parent = parent + + +class NetworkFlowGraphNodes(DirectedWeightedGraphNodes): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, *kwargs) + + if not isinstance(parent, NetworkFlowGraph): + raise TypeError('Expected parent of type NetworkFlowGraph.') + + # Get calling parent. + self._parent = parent diff --git a/tests/resources/graphs/network_flow_graph/__init__.py b/tests/resources/graphs/network_flow_graph/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/resources/graphs/network_flow_graph/edge.py b/tests/resources/graphs/network_flow_graph/edge.py new file mode 100644 index 0000000000000000000000000000000000000000..132fb6f5a1a3af16e51ff9a4ad0c69149ffab7ab --- /dev/null +++ b/tests/resources/graphs/network_flow_graph/edge.py @@ -0,0 +1,24 @@ +""" +Date: 12-03-19 +Class: CS5310 +Assignment: Graph Library +Author: Brandon Rodriguez + + +Tests for "Network Flow Edge" class. +""" + +# System Imports. +import unittest + +# User Class Imports. +from resources import NetworkFlowEdge, NetworkFlowNode + + +class TestNetworkFlowEdge(unittest.TestCase): + def setUp(self): + self.test_edge = NetworkFlowEdge('Test Edge') + + def test__node_initialization(self): + self.assertEqual(self.test_edge._edge_type, NetworkFlowEdge) + self.assertEqual(self.test_edge._node_type, NetworkFlowNode) diff --git a/tests/resources/graphs/network_flow_graph/graph.py b/tests/resources/graphs/network_flow_graph/graph.py new file mode 100644 index 0000000000000000000000000000000000000000..9ff035ce93f6e5b101da54efffdeb69090d5ac7e --- /dev/null +++ b/tests/resources/graphs/network_flow_graph/graph.py @@ -0,0 +1,56 @@ +""" +Date: 12-03-19 +Class: CS5310 +Assignment: Graph Library +Author: Brandon Rodriguez + + +Tests for "Network Flow Graph" class. +""" + +# System Imports. +import unittest + +# User Class Imports. +from resources import NetworkFlowEdge, NetworkFlowNode +from resources import NetworkFlowGraph + + +class TestNetworkFlowGraph(unittest.TestCase): + def setUp(self): + self.test_graph = NetworkFlowGraph() + + def test__node_initialization(self): + self.assertEqual(self.test_graph._edge_type, NetworkFlowEdge) + self.assertEqual(self.test_graph._graph_type, NetworkFlowGraph) + self.assertEqual(self.test_graph._node_type, NetworkFlowNode) + + def test__create(self): + # We have pretty thorough testing of the parent function. + # Thus, just test returned node is of "Network Flow" type. + node_1 = self.test_graph.nodes.create() + self.assertTrue(isinstance(node_1, NetworkFlowNode)) + + def test__remove(self): + # We have pretty thorough testing of the parent function. + # Thus, just test returned node is of "Network Flow" type. + node_1 = self.test_graph.nodes.create() + node_1 = self.test_graph.nodes.remove(node_1) + self.assertTrue(isinstance(node_1, NetworkFlowNode)) + + def test__connect(self): + # We have pretty thorough testing of the parent function. + # Thus, just test returned edge is of "Network Flow" type. + node_1 = self.test_graph.nodes.create() + node_2 = self.test_graph.nodes.create() + edge_1 = self.test_graph.nodes.connect(node_1, node_2) + self.assertTrue(isinstance(edge_1, NetworkFlowEdge)) + + def test__disconnect(self): + # We have pretty thorough testing of the parent function. + # Thus, just test returned edge is of "Network Flow" type. + node_1 = self.test_graph.nodes.create() + node_2 = self.test_graph.nodes.create() + self.test_graph.nodes.connect(node_1, node_2) + edge_1 = self.test_graph.nodes.disconnect(node_1_identifier=node_1, node_2_identifier=node_2) + self.assertTrue(isinstance(edge_1, NetworkFlowEdge)) diff --git a/tests/resources/graphs/network_flow_graph/node.py b/tests/resources/graphs/network_flow_graph/node.py new file mode 100644 index 0000000000000000000000000000000000000000..4c743d6cd49b8e6e8384b57ce17e02e39f5e1933 --- /dev/null +++ b/tests/resources/graphs/network_flow_graph/node.py @@ -0,0 +1,24 @@ +""" +Date: 12-03-19 +Class: CS5310 +Assignment: Graph Library +Author: Brandon Rodriguez + + +Tests for "Network Flow Node" class. +""" + +# System Imports. +import unittest + +# User Class Imports. +from resources import NetworkFlowEdge, NetworkFlowNode + + +class TestNetworkFlowNode(unittest.TestCase): + def setUp(self): + self.test_node = NetworkFlowNode('Test Node') + + def test__node_initialization(self): + self.assertEqual(self.test_node._edge_type, NetworkFlowEdge) + self.assertEqual(self.test_node._node_type, NetworkFlowNode)