Nodal Analysis 

Nodal analysis (NA) is based on the following simplifying assumption. As a result, it is not usable for general circuit simulation, but it is useful.

Assumption  (Simplifying Assumption) The network does not contain any voltage sources (neither independent nor controlled).

This is a curious assumption because, obviously, practical circuits typically contain voltage sources! In practice, any physical voltage source would be non-ideal. That implies that it can be converted to a non-ideal current source using Thevenin’s´theorem. However, this is not good enough as justification for this assumption, because one would expect a general-purpose circuit simulator to be able to handle ideal voltage sources. Nevertheless, it is useful to see what this assumption leads to.

A key consequence of this assumption is that the branch equations can be written in the following form:

where Y in the admitance matrix.  

NA represents circuit elements using "stamps," which are matrix entries or equations that capture the behavior of each element in the circuit. These stamps are then combined to form a system of equations that can be solved to determine the circuit variables.

In the following example we will showcase the creation of the Y matrix and the resistor stamp.

The Y matrix has size n x n, where n is the number of nodes. Our circuit to the left has only 3 nodes, so the Y matrix is 3x3. 

In the context of MNA, "stamps" refer to the mathematical equations or expressions used to describe the behavior of circuit elements (such as resistors, capacitors, inductors, voltage sources, current sources, etc.) within the circuit. These stamps are typically created based on Kirchhoff's laws (Kirchhoff's Current Law and Kirchhoff's Voltage Law) and the characteristics of the individual circuit elements. For a resistor the stamp adds simply 1/R to Yjj and -1/R to Yij. 

Let's examine the complete matrix to the left. Row and column 1 correspond to the node 0, row and column 2 to node 1 and row and column 3 to node 2.
Resistor R1 is connected between node 0 and node 1 so 1/R1 is added to Y11 and Y22. For Y21 and Y21 the entry is -1/R1.  
Similarly, for resistor R2 which is between node 1 and 2, 1/R2 is added to Y22 and Y33 and -1/R2 to Y23 and Y32.

All of that can be easily implemented in Python. For that we need the SymPy. SymPy is a Python library for symbolic mathematics.

addRES function is the resistor stamp. Y-matrix is defined initially as matrix that is of size 3-by-3 with all entries equal to zero. Than all the resistors are added calling the addRES function