Setup¶

In [1]:
import math
from math import sqrt as sqrt
import matplotlib
from matplotlib.patches import Rectangle as mpR
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

Functions¶

In [2]:
def energyProof() :
    
    fig = plt.figure(figsize = (9, 6))
    ax = fig.add_subplot(xlim = (-1.65, 1.65),
                         ylim = (-1, 1.2))

    #Clear axes.
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["bottom"].set_visible(False)
    ax.spines["left"].set_visible(False)
    ax.set_xticks([])
    ax.set_yticks([])
    
    
    #Legs.
    ax.plot([-1.6, -1.6, 1.6, 1.6],
            [-0.9, 1, 1, -0.9],
            color = '#55C667FF',
            lw = 5)
    
    #Energies.
    ax.plot([-1.6, -0.3, 1.6],
            [-0.9, 1, -0.9],
            color = '#2D708EFF',
            lw = 5)
    
    #Particles.
    ax.scatter([-1.6, -0.3, 1.6],
               [-0.9, 1, -0.9],
               color = '#440154FF',
               lw = 10,
               zorder = 2)
    
    
    text = [("b", (-1.61, 0.05), '#55C667FF', 'right', 'center', 90),
            ("b",  (1.61, 0.05), '#55C667FF', 'left', 'center', 270),
            ("a-x", (-0.95, 1.02), '#55C667FF', 'center', 'bottom', 0),
            ("a+x",  (0.65, 1.02), '#55C667FF', 'center', 'bottom', 0),
            ("√((a-x)² + b²)", (-0.85, 0.4), '#2D708EFF', 'center', 'top', 53),
            ("√((a+x)² + b²)",  (0.53, 0.38), '#2D708EFF', 'center', 'top', 317)]
        
        
    for t in text :
        plt.annotate(text = t[0],
                     xy = t[1],
                     c = t[2],
                     size = 20,
                     ha = t[3],
                     va = t[4],
                     rotation = t[5])
   
    fig.savefig("2024.12.06-0.png", bbox_inches = 'tight') 










#Creates:
#bottom - list of all n points from (0, 0)...(j/n, 0)...(1, 0).
#top - list of all n points from (0, 1)...(j/n, 1)...(1, 1).
#left - list of all n points from (0, 0)...(0, k/n)...(0, 1).
#right - list of all n points from (1, 0)...(1, k/n)...(1, 1).
#points - list of all n^2 points in nxn array from (0, 0)...(j/n, k/n)...(1, 1).
def createPoints(n) :
    
    #n+1 number from 0 to 1.
    base = [i/n for i in range(n+1)]
    
    #Points along bottom/top/left/right of square.
    bottom = []
    top = []
    left = []
    right = []
    #All points in square lattice, including border points(above)
    points = []
    
    for x in base :
        bottom.append((x, 0))
        top.append((x, 1))
        left.append((0, x))
        right.append((1, x))
        for y in base :
            points.append((x, y))
    return(bottom, top, left, right, points)




#Given two points, return the energy, the reciprocal of distance between points.    
def energyCalc(a, b) :

    return(1 / sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2))




#Given a list of particles, determines the next particle to add to minimize energy.
def nextParticle(particles, prev_energy, points) :
    
    min_energy = float('inf')
    for n in points :
        if n in (particles) : 
            next 
        else :
            energy = 0
            for p in particles :
                energy += energyCalc(n, p)
        
            if energy < min_energy :
                min_location = n
                min_energy = energy
                
    return(particles + [min_location],
           prev_energy + min_energy)




def get(n, option) :
    
    #Updates energy and location by calculating that of the current particles.
    def totalEnergyUpdate(n, location, min_location, min_energy) :
        
        #Make sure particles are unique.
        if len(set(location)) < n:
            return(min_location, min_energy)
            
        else :
            energy = 0
            #All p(p-1)/2 distances
            for i in range(n-1) :
                for j in range(i+1, n) :
                    a = location[i]
                    b = location[j]
                    energy += energyCalc(a, b)

            if energy < min_energy :  
                min_location = location
                min_energy = energy
        
        return(min_location, min_energy)
    
    
    #Setup
    z = 200
    raw = createPoints(z) 
    bottom, top, left, right, points = raw[0], raw[1], raw[2], raw[3], raw[4]
    min_location = [0, 0]*n
    min_energy = float('inf')
    
    p1 = (0, 0)
    
    if option == '3A' :
        p2 = (2-sqrt(3), 1)
        p3 = (1, 2-sqrt(3))
        location = [p1, p2, p3]
        min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)
    
    elif option == '5B' :
        p1 = (0.5, 0)
        for i in range(z+1) :
            p2 = right[i]
            p5 = left[i]
            for j in range(z+1) :
                p3 = top[z-j]
                p4 = top[j]
                location = [p1, p2, p3, p4, p5]
                min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)
                
    elif option == '5C' :
        p2 = (1, 0)
        p5 = (0, 1)
        for i in range(6296, 6316) :
                p3 = (1, i/10000)
                p4 = (i/10000, 1)
                location = [p1, p2, p3, p4, p5]
                min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)

    elif option == '6D' :
        p4 = (1, 1)
        for i in range(6600, 6620) :
            p2 = (i/10000, 0) 
            p3 = (1, 1-i/10000)
            p5 = (1-i/10000, 1)
            p6 =(0, i/10000)
            location = [p1, p2, p3, p4, p5, p6]
            min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)
    
    elif option == '6E' :
        location = [(0, 0), (1, 0), (1, 0.5), (1, 1), (0, 1), (0, 0.5)]
        min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)

    elif option == '7F' :
        p1 = (0.5, 0)
        for i in range(int(z/5)) :
            p2 = (1-i/z, 0)
            p7 = (i/z, 0)
            for j in range(5420, 5440) :
                p3 = (1, j/10000)
                p6 = (0, j/10000)
                for k in range(int(z/2)) :
                    p4 = (1-k/z, 1)
                    p5 = (k/z, 1)
                    location = [p1, p2, p3, p4, p5, p6, p7]
                    min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)   

    elif option == '7G' :
        for i in range(5150, 5250) :
            p2 = (i/10000, 0)
            p7 = (0, i/10000)
            for j in range(int(z/3)) :
                p3 = (1, j/z)
                p6 = (j/z, 1)
                for k in range(6750, 6850) :
                    p4 = (1, k/10000)
                    p5 = (k/10000, 1)        
                    location = [p1, p2, p3, p4, p5, p6, p7]
                    min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)        
    
    elif option == '8H' :
        location = [(0, 0), (0.5, 0), (1, 0), (1, 0.5),
                    (1, 1), (0.5, 1), (0, 1), (0, 0.5)]
        min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)               
        
    
    elif option == '9I' :
        p1 = (0.5, 0)
        for i in range(1) :
            p2 = (1-i, 0)
            p9 = (i, 0)
            for j in range(4520, 4540) :
                p3 = (1, j/10000)
                p8 = (0, j/10000)
                for k in range(1,2) :
                    p4 = (1, k)
                    p7 = (0, k)
                    for l in range(3180, 3200) :
                        p5 = (1-l/10000, 1)
                        p6 = (l/10000, 1) 
                        location = [p1, p2, p3, p4, p5, p6, p7, p8, p9]
                        min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)   
                        
    elif option == '9J' :
        for i in range(465, 485) :
            p2 = (i/1000, 0)
            p9 = (0, i/1000)
            for j in range(977, 997) :
                p3 = (j/1000, 0)
                p8 = (0, j/1000)
                for k in range(352, 372) :
                    p4 = (1, k/1000)
                    p7 = (k/1000, 1)
                    for l in range(777, 797) :
                        p5 = (1, l/1000)
                        p6 = (l/1000, 1) 
                        location = [p1, p2, p3, p4, p5, p6, p7, p8, p9]
                        min_location, min_energy = totalEnergyUpdate(n, location, min_location, min_energy)        
  
                    
    return(min_location, min_energy)




def particleEnergy(particles, energy, option) :
    
    p_num = str(len(particles))
    
    if option == 'Min' :
        title = 'Min. Energy'
    else :
        title = 'Alternative'
    
    x_values = [x for x, _ in particles]
    y_values = [y for _, y in particles]
    
    fig = plt.figure(figsize = (9, 6))
    ax = fig.add_subplot(xlim = (-0.1, 1.8),
                         ylim = (-0.1, 1.1))

    #Title setup.
    ax.set_title(title + ' Arrangement of ' + p_num + ' Particles', fontsize = 24)

    #Clear axes.
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["bottom"].set_visible(False)
    ax.spines["left"].set_visible(False)
    ax.set_xticks([])
    ax.set_yticks([])
    
    
    #Square.
    ax.add_patch(mpR(xy = (0, 0),
                     width = 1,
                     height = 1,
                     ec = '#55C667FF',
                     fill = False,
                     lw = 3))
    
    #Particles.
    ax.scatter(x_values,
               y_values,
               color = '#440154FF',
               lw = 10)
    
    #Annotate.
    for p in particles :
        
        text = str(p)
        
        x = p[0]
        y = p[1]
        
        xy = ((x-0.5)*0.92 + 0.5, (y-0.5)*1.08 + 0.5)
        ha = 'center'
        va = 'center'
        
        if y == 0 :
            va = 'top'
        elif y in [0.996, 1] :
            va = 'bottom'
        else :
            
            xy = ((x-0.5)*0.92 + 0.5, y)
            
            if x == 0 :
                ha = 'left'
            elif x == 1 :
                ha = 'right'
        
        if (x, y) == (0.5, 0.5) :
            xy = (0.5, 0.58)
            
        if x == 2 - sqrt(3) :
            text = '(2-√3, ' + str(y) + ')'
        elif y == 2 - sqrt(3) :
            text = '(' + str(x) + ', 2-√3)'
        
        plt.annotate(text = text,
                     xy = xy,
                     c = '#440154FF',
                     size = 16,
                     ha = ha,
                     va = va)
        
    plt.annotate(text = 'Total Energy :',
                 xy = (1.79, 0.97),
                 c = '#2D708EFF',
                 size = 24,
                 ha = 'right',
                 va = 'center')
    plt.annotate(text = str(round(energy, 4)),
                 xy = (1.79, 0.85),
                 c = '#2D708EFF',
                 size = 24,
                 ha = 'right',
                 va = 'center')
    
    fig.savefig("2024.12.06-" + p_num + option + ".png", bbox_inches = 'tight') 
In [3]:
energyProof()

2¶

In [4]:
points = createPoints(200)[4]

P2 = nextParticle([(0,0)], 0, points)
print(P2)
particleEnergy(P2[0], P2[1], 'Min')
([(0, 0), (1.0, 1.0)], 0.7071067811865475)

3¶

In [5]:
P3 = nextParticle(P2[0], P2[1], points)
print(P3)
particleEnergy(P3[0], P3[1], 'Min')
([(0, 0), (1.0, 1.0), (0.0, 1.0)], 2.7071067811865475)
In [6]:
P3A = get(3, '3A')
print(P3A)
particleEnergy(P3A[0], P3A[1], 'Alt')
([(0, 0), (0.2679491924311228, 1), (1, 0.2679491924311228)], 2.897777478867205)

4¶

In [7]:
P4 = nextParticle(P3[0], P3[1], points)
print(P4)
particleEnergy(P4[0], P4[1], 'Min')
([(0, 0), (1.0, 1.0), (0.0, 1.0), (1.0, 0.0)], 5.414213562373095)

5¶

In [8]:
P5 = nextParticle(P4[0], P4[1], points)
print(P5)
particleEnergy(P5[0], P5[1], 'Min')
([(0, 0), (1.0, 1.0), (0.0, 1.0), (1.0, 0.0), (0.5, 0.5)], 11.071067811865476)
In [9]:
P5B = get(5, '5B')
print(P5B)
particleEnergy(P5B[0], P5B[1], 'Alt1')
([(0.5, 0), (1, 0.0), (1.0, 1), (0.0, 1), (0, 0.0)], 11.203067944372927)
In [10]:
P5C = get(5, '5C')
print(P5C)
particleEnergy(P5C[0], P5C[1], 'Alt2')
([(0, 0), (1, 0), (1, 0.6306), (0.6306, 1), (0, 1)], 11.36070778801192)

6¶

In [11]:
P6 = nextParticle(P5[0], P5[1], points)
print(P6)
particleEnergy(P6[0], P6[1], 'Alt1')
([(0, 0), (1.0, 1.0), (0.0, 1.0), (1.0, 0.0), (0.5, 0.5), (0.0, 0.5)], 18.85992219386531)
In [12]:
P6D = get(6, '6D')
print(P6D)
particleEnergy(P6D[0], P6D[1], 'Alt2')
([(0, 0), (0.6614, 0), (1, 0.3386), (1, 1), (0.3386, 1), (0, 0.6614)], 18.76174582585402)
In [13]:
P6E = get(6, '6E')
print(P6E)
particleEnergy(P6E[0], P6E[1], 'Min')
([(0, 0), (1, 0), (1, 0.5), (1, 1), (0, 1), (0, 0.5)], 17.99192232637276)

7¶

In [14]:
P7 = nextParticle(P6E[0], P6E[1], points)
print(P7)
particleEnergy(P7[0], P7[1], 'Alt1')
([(0, 0), (1, 0), (1, 0.5), (1, 1), (0, 1), (0, 0.5), (0.5, 0.0)], 26.60920383311878)
In [15]:
P7F = get(7, '7F')
print(P7F)
particleEnergy(P7F[0], P7F[1], 'Min')
([(0.5, 0), (1.0, 0), (1, 0.5424), (1.0, 1), (0.0, 1), (0, 0.5424), (0.0, 0)], 26.548829117091806)
In [16]:
P7G = get(7, '7G')
print(P7G)
particleEnergy(P7G[0], P7G[1], 'Alt2')
([(0, 0), (0.5214, 0), (1, 0.0), (1, 0.6849), (0.6849, 1), (0.0, 1), (0, 0.5214)], 26.94062754987074)

8¶

In [17]:
P8 = nextParticle(P7F[0], P7F[1], points)
print(P8)
particleEnergy(P8[0], P8[1], 'Alt')
([(0.5, 0), (1.0, 0), (1, 0.5424), (1.0, 1), (0.0, 1), (0, 0.5424), (0.0, 0), (0.5, 1.0)], 36.288454855413775)
In [18]:
P8H = get(8, '8H')
print(P8H)
particleEnergy(P8H[0], P8H[1], 'Min')
([(0, 0), (0.5, 0), (1, 0), (1, 0.5), (1, 1), (0.5, 1), (0, 1), (0, 0.5)], 36.22648533986481)

9¶

In [19]:
P9 = nextParticle(P8H[0], P8H[1], points)
print(P9)
particleEnergy(P9[0], P9[1], 'Alt1')
([(0, 0), (0.5, 0), (1, 0), (1, 0.5), (1, 1), (0.5, 1), (0, 1), (0, 0.5), (0.5, 0.5)], 49.88333958935719)
In [20]:
P9I = get(9, '9I')
print(P9I)
particleEnergy(P9I[0], P9I[1], 'Min')
([(0.5, 0), (1, 0), (1, 0.4531), (1, 1), (0.681, 1), (0.319, 1), (0, 1), (0, 0.4531), (0, 0)], 49.75867057415001)
In [21]:
P9J = get(9, '9J')
print(P9J)
particleEnergy(P9J[0], P9J[1], 'Alt2')
([(0, 0), (0.472, 0), (0.996, 0), (1, 0.367), (1, 0.789), (0.789, 1), (0.367, 1), (0, 0.996), (0, 0.472)], 50.485548145964074)

Rohan Lewis¶

2024.12.09¶