Search

Classes For Graphs and Directed Graphs In Python: Graph Theory

In computer science and mathematics, graphs are ubiquitous. They are just everywhere. We use graphs to solve a lot of problems that involve relationships. Since 1735 when the Swiss Mathematician, Leonhard Euler, used what we now know as graph theory to solve the Seven Bridges of Königsberg problem, graphs have become a brand name of sorts. That is why I decided to write a post on graphs and explore graphs in subsequent posts.

python graphs and directed graphs

 

What are graphs?

In simple terms, graphs are structures used to represent the relationship between objects (called vertices or nodes) where two objects (or nodes) have an edge connecting them if they are related. Diagrammatically, they are depicted with a set of dots or circles for the objects or nodes, and related objects are joined by lines called edges.

The graph below has 6 nodes or vertices, and 7 edges.


 

The edges of a graph may be directed or undirected.

I will be writing code for both directed and undirected graphs. What made me attracted to writing code on graphs was because they are used in every area of life. From scientists to businesses, graphs are used to model solutions to problems.

So, let’s start with writing classes for graphs and we will implement them.

First, we’ll create a class for a Node and an Edge.

A node is just an object in a graph. One attribute every object has is a Name. So, we’ll give our node a name attribute to start with. Here is the code for the Node class.

    
class Node(object):

    def __init__(self, name):
        ''' assumes name a string '''
        self.name = name

    def get_name(self):
        return self.name

    def __str__(self):
        return self.name

Every instance of a Node, as you can see from the code, has a name and each instance has a method, get_name, which you can use to retrieve the name.

An edge is a relation connector between objects. If two objects are connected to each other by a relationship, they will have an edge between them. Edges can be directed or non-directed. Let’s model the Edge class to start with.

    
class Edge(object):

    def __init__(self, src, dest):
        '''assume src and dest are nodes '''
        self.src = src
        self.dest = dest

    def get_source(self):
        return self.src

    def get_destination(self):
        return self.dest

    def __str__(self):
        return self.src.get_name() + '-->' + \
            self.dest.get_name()

From the code you can see that each instance of an Edge has a source node, self.src, and a destination node, self.dest. On creation of a node the source and destination nodes have to be passed as arguments to the constructor, __init__. Then I added a special method for representing an Edge as a string of source and destination nodes, __str__(). This would make for easy printing.

Now that we have the Node and Edge classes, let us go on to model the directed graphs and undirected graphs.

Directed graphs in Python code

A directed graph is a graph in which edges have orientations. The relationship in directed graphs goes one-sided and never both way. The edges are represented by arrows.

A simple class for a directed graph might be written in the following way:

    
class Digraph(object):
    # nodes is a list of the nodes in the graph
    # edges is a dict mapping each node to 
    # a list of its children 
    def __init__(self):
        self.nodes = []
        self.edges = {}

    def add_node(self, node):
        if node in self.nodes:
            raise ValueError('Duplicate Node')
        else:
            self.nodes.append(node)
            self.edges[node] = []

    def add_edge(self, edge):
        src = edge.get_source()
        dest = edge.get_destination()
        if not (src in self.nodes and dest in self.nodes):
            raise ValueError('Node not in graph')
        self.edges[src].append(dest)

    def children_of(self, node):
        return self.edges[node]

    def has_node(self, node):
        return node in self.nodes

    def __str__(self):
        result = ''
        for src in self.nodes:
            for dest in self.edges[src]:
                result = result + src.get_name() + \
                    '-->' + dest.get_name() + '\n'
        return result[:-1] # remove last newline

The class, Digraph, represents a class for objects of a directed graph. If you look at the constructor, we are representing all the nodes in the graph as a list, while the edges are represented by a mapping of nodes to child nodes which mapping goes only one way. Therefore, a dictionary data structure was used for this mapping. To have a graph, it needs nodes. To add a node, we use the method add_node that takes a node as its sole argument. To add a node, we need first to check if the node already exists in the list of nodes and if it does, the method raises a ValueError. If not, it then appends the node to the list of nodes in the graph and then creates a mapping for that node with its values as an empty list that would later be populated when edges are added. To add an edge to the graph, we use the add_edge method. We first initialize the source and destination nodes of the edge, and before adding the edge we check that the source and destination nodes are already in the list of nodes for the graph. If they are not in the list, we raise a ValueError exception. If no exception is raised, a directed edge is created with the source, src, mapped to its value, the destination node, dest. The class also has complementary methods, children_of, that would bring out a list of the nodes connected to that node as source, and also another method, has_node, that returns a Boolean value after evaluating whether the node in question is in the list of nodes for the graph.

That sums up our directed graph, Digraph, class. Now, let’s show that the code works. Let’s implement it by creating an instance of a directed graph, or Digraph. The Digraph instance I will be creating will be based on the directed graph below with 5 nodes and 6 edges. 

python directed graph

 

The only new code is the driver code that creates a Digraph instance. For the sake of brevity, I would recommend that you read the driver code starting from line 67 down to line 106. It is really an exciting code. I hope you appreciate it.

Now the question I asked myself is: why create a class for a graph and not just write code direct? This is because I would be reusing the code in the future. So, we will be coming back to this code for solving problems involving graphs in the future. Maybe you could bookmark this code for the Digraph class. You can download the file here, directed_graph.py.

Undirected graphs or simple graphs in Python code.

An undirected graph or graph for short is a connection between a pair of nodes using their edges. The edges can go both ways which distinguishes it from directed graphs that have orientations.

Now while writing the code for undirected graphs, I ran into a dilemma about inheritance. I was stuck between which graph should inherit from which. Should a directed graph inherit from a undirected graph or should it be vice versa? I decided that it was best for a graph to inherit from a directed graph. This was because instances of graphs can substitute for instances of digraphs and still add one more behavior by making the relationship go the other way. But instances of digraphs cannot stand as substitutes for instances of graphs; digraphs relationship goes only one way. Therefore, I decided to make digraph the superclass and graph the subclass.

Now, this is the code for the class graph.

    
class Graph(Digraph):

    def add_edge(self, edge):
        Digraph.add_edge(self, edge)
        rev = Edge(edge.get_destination(), edge.get_source())
        Digraph.add_edge(self, rev)                                            

Notice that the class, Graph, is inheriting from Digraph so it shares the same attributes with Digraph instances but it only overrides the add_edge method of Digraph. In the add_edge method of Graph I made it that the relationship can go both ways i.e every node in a relationship or edge is both a source and destination node for that edge.

So, for a little implementation that creates an instance of a Graph, I will be modeling the Graph pictured below:

python graph example

 

Run the code and notice the differences between this instance of a Graph and instances of a Digraph. The driver code that creates the Graph instances starts at line 73. You can alternatively download the code and run it on your own machine, graph.py script, so you can bookmark it.

I hope to see you in the future when we begin solving problems with graphs like the traveling salesman problem. To receive updates when I post new articles, just subscribe to my blog.

Happy pythoning.

How To Reverse String In Python: 3 Techniques

After writing the post on reversing lists in python, I got a good response that I decided it would also be fine if I approach a similar concept in python: how to reverse a string in python.

python reverse string

 

One thing that makes people find this subject difficult is because python does not have a string method that is specifically built for reversing strings just like we have for lists. If there was one, that would have made our task easier because it would be optimized. So you have to be creative in looking for ways to reverse python strings. In this post, I outline three methods you can reverse strings in python as well as their timing characteristics.

First, using the python slice technique

The python slice technique, as I explained in the post about reversing lists through slicing, involves taking a slice of a sequence (and strings are also sequences) through definite start, stop, and step parameters. The slice notation in python is [start: stop : step] where start is where you want to start the slice, stop is at the index you want to stop the slice and step is the steps you take through the index while iterating through the items in the string. To reverse a string using the python slice technique, you just need to use this code on the string: string_name[ : : -1].

What the code above does is to copy the string, string_name, from the beginning to the end backwards.

Here is an example so you can see it for yourself.

Nice and easy not so? This method does not change the original string. In fact, as you must know, strings are immutable.

This is the method I prefer for reversing python strings.

Second, using the built-in reversed function.

I explained the reversed function on the post for reversing lists. But one more explanation would be succinct here. The syntax for the reversed function is: reversed(seq). As you can see, the function takes any sequence and reverses it. A string is also a sequence as I explained on the iterables post. When the string is reversed the function returns an iterator. What you do here is cast the iterator to a string. I think that is what gives this function an overhead, the process of casting the iterator to a string, otherwise it is very good and fast. You use the str.join(iterable) method of the string class to cast the iterator to a string.

Here is code that shows how to use the function and also cast it to a string.

This method is very succinct and readable across all levels of python skill.

Third, using a for loop and storing the characters backwards.

With this method all you need to do is use a for loop to iterate through the characters in the string, then you store the characters backwards in a new string. Very convenient and easy to understand.

Here is the code:

I hope you found the code to be fun.

Now, the question most persons ask is: Which is faster or which uses less system memory?

Let’s answer that question by timing the execution of each of the string reverse techniques in python and decide on which is faster or more optimized.

Timing all three techniques.

Try running the following code:

When you run it you will notice that the python slice technique took considerably lesser time than all the others while the for loop took more time. That is why I use the slice technique to reverse my strings.

There was a time when someone told me that during an interview question the interviewer told him that the slice technique is not optimized for reversing strings. I laughed. I have not yet seen anything better than the python slice technique for reversing strings. For now it is the fastest of all the methods I know of and I have outlined the three useful I use here. I use the for loop when I am lazy and just want to be unpythonic.

So, thanks for reading. I believe that now you have techniques you can use to reverse your strings. Leave a comment below if you have any. Also, do not fail to subscribe to my blog so you can be receiving useful updates the moment I post new articles.

Happy pythoning.

Breakthrough 3D Printing Of Heart For Treating Aortic Stenosis

When a narrowed aortic valve fails to open properly and thereby the pumping of blood from the heart to the aorta is obstructed, this might result in a condition called aortic valve stenosis. Aortic stenosis is one of the most common cardiovascular conditions in the elderly and affects about 2.7 million adults over the age of 75 in North America. If the doctors decide that the condition is severe, they may carry out a minimally invasive heart procedure to replace the valve. This procedure is called transcatheter aortic valve replacement (TAVR). But this catheterization procedure is not without some risks which might include bleeding, stroke, heart attack or even death. That is why it is important that the doctors take all care to reduce the risks. The TAVR procedure is less invasive than open heart surgery to repair the damaged valves,

3D printing of heart

In a new paper published in Science Advances, a peer-reviewed scientific journal published by the American Association for the Advancement of Science (AAAS), some researchers from the University of Minnesota along with their collaborators have been able to produce a new technique that involves 3D printing of the aortic valve along with creating lifelike models of the aortic valve and surrounding structures which models mimic the look and feel of the valve. These 3D printing would possibly help reduce the risks for doctors who want to carry out a TAVR procedure on a patient.

Precisely, they 3D printed a model of the aortic root. The aortic root is a section of the aorta that is closest to the heart and attached to the heart. Some of the components of the aortic root include the aortic valve, which is prone to aortic stenosis in the elderly, along with the openings of the coronary artery. The left ventricle muscle and the ascending aorta which are close to the aortic root are also not left out in the model.

The models include specialized 3D printing soft sensor arrays built into the structure that prints the organs for each patient. The 3D printing process is also customized. The authors believe that this organ model will be used by doctors all over the world to improve the outcomes for patients who will be subject to invasive procedures when treating aortic stenosis.

Before the models are produced CT scans of the patient’s aortic root are made so that the printing will mimic the exact shape of the patient's organ. Then specialized silicone-based inks are used to do the actual printing in order to match the exact feel of the patient's heart. These inks were specially built for this process because commercial printers in the market can print 3D shapes but they cannot be able to reflect the real feel of the heart’s organs which are soft tissues. The initial heart tissue that were used for the test of the 3D printers were obtained from the University of Minnesota's Visible Heart Laboratory. The researchers found that the specialized 3D printers produced models that they wanted, models that mimic the shape and the feel of the aortic valve at the heart.

To watch a video of how the 3D printers work, I encourage you to play the video below. You would find it interesting.


The researchers are happy with what they have achieved.

“Our goal with these 3D-printed models is to reduce medical risks and complications by providing patient-specific tools to help doctors understand the exact anatomical structure and mechanical properties of the specific patient’s heart,” said Michael McAlpine, a University of Minnesota mechanical engineering professor and senior researcher on the study. “Physicians can test and try the valve implants before the actual procedure. The models can also help patients better understand their own anatomy and the procedure itself.”

These models will surely be of help to physicians who will use them to practice on how they will carry out their catheterization procedures on the real heart. Physicians will soon have the ability to practice beforehand on the size and placement of the catheter device on patients before carrying out the real procedure thereby reducing the risks involved. One good thing about the integrated sensors that are fitted into the 3D models is that they will provide physicians with electronic pressure feedback which will guide them in determining and selecting the optimal position of the catheter when being placed into the aorta of a patient.

But the researchers do not think these are the only use cases for their findings or the models. They aim to go beyond that.

“As our 3D-printing techniques continue to improve and we discover new ways to integrate electronics to mimic organ function, the models themselves may be used as artificial replacement organs,” said McAlpine, who holds the Kuhrmeyer Family Chair Professorship in the University of Minnesota Department of Mechanical Engineering. “Someday maybe these ‘bionic’ organs can be as good as or better than their biological counterparts.”

I think these are laudable futuristic goals. If they could achieve their ambition, then McAlpine would be solving a problem that gives sleepless nights to many physicians who have to operate on elderly patients with weak aortic valves.

Because this is a problem-solving innovative solution to a challenging problem, I decided to include it in my blog. I hope you enjoyed reading about the achievements of McAlpine and his colleagues. I wish that they go further than just helping physicians have 3D models but be able to make those models replace weak natural organs.

In addition to McAlpine, the team included University of Minnesota researchers Ghazaleh Haghiashtiani, co-first author and a recent mechanical engineering Ph.D. graduate who now works at Seagate; Kaiyan Qiu, another co-first author and a former mechanical engineering postdoctoral researcher who is now an assistant professor at Washington State University; Jorge D. Zhingre Sanchez, a former biomedical engineering Ph.D. student who worked in the University of Minnesota’s Visible Heart Laboratories who is now a senior R&D engineer at Medtronic; Zachary J. Fuenning, a mechanical engineering graduate student; Paul A. Iaizzo, a professor of surgery in the Medical School and founding director of the U of M Visible Heart Laboratories; Priya Nair, senior scientist at Medtronic; and Sarah E. Ahlberg, director of research & technology at Medtronic.

This research was funded by Medtronic, the National Institute of Biomedical Imaging and Bioengineering of the National Institutes of Health, and the Minnesota Discovery, Research, and InnoVation Economy (MnDRIVE) Initiative through the State of Minnesota. Additional support was provided by University of Minnesota Interdisciplinary Doctoral Fellowship and Doctoral Dissertation Fellowship awarded to Ghazaleh Haghiashtiani.

You can read the full research paper, entitled "3D printed patient-specific aortic root models with internal sensors for minimally invasive applications," at the Science Advances website.

Matched content