diff --git a/__init__.py b/__init__.py index d5917feb3957f1c4106482c92e09f43acdaad2ad..925765359b3e7057b8cf38a1d5aa35ee1e943f7d 100644 --- a/__init__.py +++ b/__init__.py @@ -11,5 +11,8 @@ __all__ = [ 'BasicEdge', 'BasicNode', 'BasicGraph', 'DirectedEdge', 'DirectedNode', 'DirectedGraph', 'StateMachineEdge', 'StateMachineNode', 'StateMachineGraph', + 'WeightedGraph', 'WeightedEdge', 'WeightedNode', + + 'DirectedWeightedEdge', 'DirectedWeightedNode', 'DirectedWeightedGraph', ] diff --git a/main.py b/main.py index cccf74b80f96e025ee9f2e3c7842d905f6d15940..9cc40752d356cd581db624397919409fc481d0cf 100644 --- a/main.py +++ b/main.py @@ -16,7 +16,9 @@ from random import randint from resources import logging as init_logging from resources import BasicEdge, BasicGraph, BasicNode from resources import DirectedEdge, DirectedGraph, DirectedNode +from resources import DirectedWeightedEdge, DirectedWeightedGraph, DirectedWeightedNode from resources import StateMachineEdge, StateMachineGraph, StateMachineNode +from resources import WeightedEdge, WeightedGraph, WeightedNode # Initialize Logger. @@ -31,7 +33,7 @@ def test_graph(): logger.info('Creating and displaying Test Graph...') # Create graph. - graph = StateMachineGraph() + graph = DirectedWeightedGraph() # Create some nodes. node_1 = graph.nodes.create('A') @@ -39,34 +41,12 @@ def test_graph(): node_3 = graph.nodes.create('C') node_4 = graph.nodes.create('D') - node_5 = graph.nodes.create('AA') - node_6 = graph.nodes.create('BB') - node_7 = graph.nodes.create('CC') - node_8 = graph.nodes.create('DD') - # Connect nodes. - graph.nodes.connect(node_1, node_1, 'A') graph.nodes.connect(node_1, node_2, 'a') graph.nodes.connect(node_2, node_3, 'b') graph.nodes.connect(node_4, node_3, 'c') - graph.nodes.connect(node_4, node_2, ['a', 'b']) graph.nodes.connect(node_4, node_1, 'd') - graph.nodes.connect(node_5, node_6, 'a') - graph.nodes.connect(node_6, node_7, 'b') - graph.nodes.connect(node_8, node_7, 'c') - graph.nodes.connect(node_8, node_6, ['a', 'b']) - graph.nodes.connect(node_8, node_5, 'd') - - # Add initial/final states. - node_1.toggle_node_state_initial() - node_4.toggle_node_state_initial() - node_3.toggle_node_state_final() - - node_5.toggle_node_state_initial() - node_8.toggle_node_state_initial() - node_7.toggle_node_state_final() - # Display graph mapping. graph_title = 'Custom Graph Library - Graph Visual Mapping<br>Test Graph' graph.display.draw_graph_map(graph_title) diff --git a/resources/__init__.py b/resources/__init__.py index ac9353c773530ef9bbf9a9b83e53622080823c43..a56c5a64b7e6cd4f0f1c5417ca807e0ffd3dbc35 100644 --- a/resources/__init__.py +++ b/resources/__init__.py @@ -11,5 +11,8 @@ __all__ = [ 'BasicEdge', 'BasicNode', 'BasicGraph', 'DirectedEdge', 'DirectedNode', 'DirectedGraph', 'StateMachineEdge', 'StateMachineNode', 'StateMachineGraph', + 'WeightedEdge', 'WeightedNode', 'WeightedGraph', + + 'DirectedWeightedEdge', 'DirectedWeightedNode', 'DirectedWeightedGraph', ] diff --git a/resources/graphs/__init__.py b/resources/graphs/__init__.py index 5baf47a26d758b0da4ea4c99f86feafb760dcf07..c15d5351311cc9c8a975c42f40839f8590c03f16 100644 --- a/resources/graphs/__init__.py +++ b/resources/graphs/__init__.py @@ -5,6 +5,7 @@ # Import files/values we want to be available to other folders. from .basic_graph import * from .directed_graph import * +from .directed_weighted_graph import * from .state_machine import * from .weighted_graph import * @@ -14,5 +15,8 @@ __all__ = [ 'BasicEdge', 'BasicNode', 'BasicGraph', 'DirectedEdge', 'DirectedNode', 'DirectedGraph', 'StateMachineEdge', 'StateMachineNode', 'StateMachineGraph', + 'WeightedEdge', 'WeightedNode', 'WeightedGraph', + + 'DirectedWeightedEdge', 'DirectedWeightedNode', 'DirectedWeightedGraph', ] diff --git a/resources/graphs/directed_weighted_graph/__init__.py b/resources/graphs/directed_weighted_graph/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..85e003d276b839d6357a62ddc14f142269fd1c09 --- /dev/null +++ b/resources/graphs/directed_weighted_graph/__init__.py @@ -0,0 +1,13 @@ +""" +"Directed, Weighted Graph" folder importing definitions. +""" + +# Import files/values we want to be available to other folders. +from .components import DirectedWeightedEdge, DirectedWeightedNode +from .graph import DirectedWeightedGraph + + +# Define imports when using the * flag on this folder. +__all__ = [ + 'DirectedWeightedEdge', 'DirectedWeightedNode', 'DirectedWeightedGraph', +] diff --git a/resources/graphs/directed_weighted_graph/components.py b/resources/graphs/directed_weighted_graph/components.py new file mode 100644 index 0000000000000000000000000000000000000000..55ba95397a0fcac02e6d8a5432e90dc25b4a647a --- /dev/null +++ b/resources/graphs/directed_weighted_graph/components.py @@ -0,0 +1,58 @@ +""" +Date: 12-03-19 +Class: CS5310 +Assignment: Graph Library +Author: Brandon Rodriguez + + +Edge and Node classes for a "directed, weighted 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_graph.components import DirectedEdge, DirectedNode +from ..weighted_graph.components import WeightedEdge, WeightedNode + + +#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 DirectedWeightedEdge(DirectedEdge, WeightedEdge): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Define expected class types (should all be of "Directed" type). + # This is necessary for inheritance, or else child classes will only have access to parent functions. + self._edge_type = DirectedWeightedEdge + self._node_type = DirectedWeightedNode + + +class DirectedWeightedNode(DirectedNode, WeightedNode): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Define expected class types (should all be of "Directed" type). + # This is necessary for inheritance, or else child classes will only have access to parent functions. + self._edge_type = DirectedWeightedEdge + self._node_type = DirectedWeightedNode diff --git a/resources/graphs/directed_weighted_graph/graph.py b/resources/graphs/directed_weighted_graph/graph.py new file mode 100644 index 0000000000000000000000000000000000000000..54badf4bc75079cb6017c07219bf810eea1c5e1a --- /dev/null +++ b/resources/graphs/directed_weighted_graph/graph.py @@ -0,0 +1,86 @@ +""" +Date: 12-03-19 +Class: CS5310 +Assignment: Graph Library +Author: Brandon Rodriguez + + +Graph class for a "directed, weighted graph" (Has edge weights and edge directions). +Parent structure containing various Nodes and Edges. +""" + +# System Imports. + +# User Class Imports. +from .components import DirectedWeightedEdge, DirectedWeightedNode +from ..directed_graph.graph import DirectedGraph, DirectedGraphDisplay, DirectedGraphEdges, DirectedGraphNodes +from ..weighted_graph.graph import WeightedGraph, WeightedGraphDisplay, WeightedGraphEdges, WeightedGraphNodes + + +#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 DirectedWeightedGraph(DirectedGraph, WeightedGraph): + 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 = DirectedWeightedEdge + self._graph_type = DirectedWeightedGraph + self._node_type = DirectedWeightedNode + + # Get associated child classes. + self.display = DirectedWeightedGraphDisplay(self) + self.edges = DirectedWeightedGraphEdges(self) + self.nodes = DirectedWeightedGraphNodes(self) + + +class DirectedWeightedGraphDisplay(DirectedGraphDisplay, WeightedGraphDisplay): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, *kwargs) + + if not isinstance(parent, DirectedWeightedGraph): + raise TypeError('Expected parent of type DirectedWeightedGraph.') + + # Get calling parent. + self._parent = parent + + +class DirectedWeightedGraphEdges(DirectedGraphEdges, WeightedGraphEdges): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, *kwargs) + + if not isinstance(parent, DirectedWeightedGraph): + raise TypeError('Expected parent of type DirectedWeightedGraph.') + + # Get calling parent. + self._parent = parent + + +class DirectedWeightedGraphNodes(DirectedGraphNodes, WeightedGraphNodes): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, *kwargs) + + if not isinstance(parent, DirectedWeightedGraph): + raise TypeError('Expected parent of type DirectedWeightedGraph.') + + # Get calling parent. + self._parent = parent