Milkmaid and Cow Problem Display Matplotlib

mail@pastecode.io avatar
unknown
python
2 months ago
4.5 kB
2
Indexable
Never
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize
from matplotlib.widgets import Slider
import random
from matplotlib import style

def find_root(a, b, x_1, x_2, y_1, y_2, tol=1e-5, max_iter=100):
    if distanceDeriv(a, x_1, x_2, y_1, y_2) * distanceDeriv(b, x_1, x_2, y_1, y_2) > 0:
        return None  # No root in this interval
    for _ in range(max_iter):
        c = (a + b) / 2
        if distanceDeriv(c, x_1, x_2, y_1, y_2) == 0 or (b - a) / 2 < tol:
            return c  # Found the root within tolerance
        if distanceDeriv(c, x_1, x_2, y_1, y_2) * distanceDeriv(a, x_1, x_2, y_1, y_2) < 0:
            b = c
        else:
            a = c
    return (a + b) / 2  # Return the midpoint as an approximation

def secureRoot(a, b, x_1, x_2, y_1, y_2):
    root = None
    while root is None:
        root = find_root(a, b, x_1, x_2, y_1, y_2, tol=1e-5, max_iter=100)
        if distanceDeriv((root-0.0000001), x_1, x_2, y_1, y_2) < 0 and distanceDeriv((root+0.0000001), x_1, x_2, y_1, y_2) > 0 and root is not None:
            return root
        if root is None:
            while root is None:
                a = random.randint(-10, 10)
                b = random.randint(-10, 10)
                if a > b:
                    a = random.randint(-10, 10)
                    b = random.randint(-10, 10)
                root = find_root(a, b, x_1, x_2, y_1, y_2, tol=1e-5, max_iter=100)
    return root

# Create the figure and axis
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.30)

def f(x):
    return x**2

def df(x):
    return 2*x

def distanceDeriv(x, x_1, x_2, y_1, y_2):

    return ((x-x_1)+df(x)*(f(x)-y_1))/(((x-x_1)**2+(f(x)-y_1)**2)**(1/2)) + ((x-x_2)+df(x)*(f(x)-y_2))/(((x-x_2)**2+(f(x)-y_2)**2)**(1/2))


# Define the initial values for a, b, and c
initial_x_1 = 1.0
initial_x_2 = 1.0
initial_y_1 = 0.0
initial_y_2 = 0.0
InitialPointsX = [initial_x_1, initial_x_2, secureRoot(-10, 10, initial_x_1, initial_x_2, initial_y_1, initial_y_2)]
InitialPointsY = [initial_y_1, initial_y_2, f(secureRoot(-10, 10, initial_x_1, initial_x_2, initial_y_1, initial_y_2))]


# Define the function to plot
x = np.linspace(-10, 10, 400)
initial_y = distanceDeriv(x, initial_x_1, initial_x_2, initial_y_1, initial_y_2)
#Uncomment this if you wanna see the derivative function
#line, = ax.plot(x, initial_y, label='D\'(x)')
PointandLine1, = ax.plot([initial_x_1, secureRoot(-10, 10, initial_x_1, initial_x_2, initial_y_1, initial_y_2)], [initial_y_1, f(secureRoot(-10, 10, initial_x_1, initial_x_2, initial_y_1, initial_y_2))], 'ro-')
PointandLine2, = ax.plot([secureRoot(-10, 10, initial_x_1, initial_x_2, initial_y_1, initial_y_2), initial_x_2], [f(secureRoot(-10, 10, initial_x_1, initial_x_2, initial_y_1, initial_y_2)), initial_y_2], 'ro-')
# Define sliders
slider_x_1 = Slider(plt.axes([0.1, 0.20, 0.8, 0.03]), label='x_1', valmin=x.min(), valmax=x.max(), valinit=initial_x_1, valstep=0.1)
slider_x_2 = Slider(plt.axes([0.1, 0.10, 0.8, 0.03]), label='x_2', valmin=x.min(), valmax=x.max(), valinit=initial_x_2, valstep=0.1)
slider_y_1 = Slider(plt.axes([0.1, 0.15, 0.8, 0.03]), label='y_1', valmin=-f(x.min()), valmax=f(x.max()), valinit=initial_y_1, valstep=0.1)
slider_y_2 = Slider(plt.axes([0.1, 0.05, 0.8, 0.03]), label='y_2', valmin=-f(x.min()), valmax=f(x.max()), valinit=initial_y_2, valstep=0.1)
ax.plot(x,f(x))
cow = ax.annotate("Cow", xy=(initial_x_2, initial_y_2), xytext=(initial_x_2-0.55, initial_y_2+3))
milkmaid = ax.annotate("Milkmaid", xy=(initial_x_1, initial_y_1), xytext=(initial_x_1-1.25, initial_y_1+3))
#Define function to update plot when sliders change
def update(val):
    x_1 = slider_x_1.val
    x_2 = slider_x_2.val
    y_1 = slider_y_1.val
    y_2 = slider_y_2.val
    root = secureRoot(-10, 10, x_1, x_2, y_1, y_2)
    y = distanceDeriv(x, x_1, x_2, y_1, y_2)
    #Uncomment this if you wanna see the derivative function
    #line.set_ydata(y)
    #line.set_label('D\'(x)')
    PointandLine1.set_xdata([x_1, root])
    PointandLine1.set_ydata([y_1, f(root)])
    PointandLine2.set_xdata([root, x_2])
    PointandLine2.set_ydata([f(root), y_2])
    print(root)
    cow.set_x(x_2-0.55)
    cow.set_y(y_2+3)
    milkmaid.set_x(x_1-1.25)
    milkmaid.set_y(y_1+3)
    plt.draw()



slider_x_1.on_changed(update)
slider_x_2.on_changed(update)
slider_y_1.on_changed(update)
slider_y_2.on_changed(update)

plt.show()
Leave a Comment