These are the libraries I imported for the Python project. I chose Python because I wanted to focus on creating a physics simulation rather than on the underlying graphical display and specialized arrays.
numPendulums is the variable set by user input, which randomly assigns lengths, masses, and angles to the pendulums within the coupled simulation.
I initialized a timesteps list, since the simulation is precomputed and then converted into a Matplotlib animation.
I chose to utilize the Sympy library so it would be clearer to me how the recursive formulas used in modeling a pendulum are reflected in the simulation. In essense, the first pendulums position is dependent on itself, but its acceleration is dependent on every pendulum. For the bottom, its positions depends on all of the links above, but it accelerates independently.
The relationship I described above creates a system of equations of length N, where N is the number of pendulums and therefore the number of accelerations to be calculated. These systems of equations are added to a list, where a Jacobian matrix is created to compute how each change in the system affects the resulting state. This is a method of optimization: I first solved the system symbolically, then numerically, and this represents the final optimization.
The tqdm library is used here as a quality-of-life feature, since I ran this code many times and found it helpful for tracking speed and progress. The state list, unlike timesteps, is overwritten at every frame because each new frame depends only on the previous one, not on the full collection of intervals. Each state is then added to timesteps.
The function animate is defined and called by Matplotlib at every frame. It checks the corresponding index and updates the positions of the pendulums on the graph.