Fix branches.
This commit is contained in:
parent
0553d80379
commit
08c4b1f790
|
@ -191,3 +191,4 @@ plt.plot(res_xs, res_ys)
|
||||||
plt.plot(xs, ys, 'ro')
|
plt.plot(xs, ys, 'ro')
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
|
108
h2/mbc.py
108
h2/mbc.py
|
@ -1,21 +1,109 @@
|
||||||
|
import random
|
||||||
import statistics
|
import statistics
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from typing import List, Set
|
from enum import Enum, auto
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
from scipy.optimize import linprog
|
||||||
|
|
||||||
Point = namedtuple('Point', 'x y')
|
Point = namedtuple('Point', 'x y')
|
||||||
|
|
||||||
|
|
||||||
def mbc_ch(points: Set[Point]):
|
def gen_point(lower: int, upper: int) -> Point:
|
||||||
|
a = random.uniform(lower, upper)
|
||||||
|
b = random.uniform(lower, upper)
|
||||||
|
|
||||||
|
x_i = random.uniform(lower, upper)
|
||||||
|
p_i = Point(x_i, a * x_i + b)
|
||||||
|
p_i = Point(a, b)
|
||||||
|
return p_i
|
||||||
|
|
||||||
|
|
||||||
|
def display(points: Set[Point], hull: Set[Point]):
|
||||||
|
x = [point.x for point in points]
|
||||||
|
y = [point.y for point in points]
|
||||||
|
|
||||||
|
h_x = [point.x for point in hull]
|
||||||
|
h_y = [point.y for point in hull]
|
||||||
|
|
||||||
|
plt.plot(h_x, h_y, 'ro')
|
||||||
|
|
||||||
|
plt.scatter(x, y)
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
def display_line_only(points: Set[Point], slope: int, intercept: int, line_points: Set[Point]):
|
||||||
|
x = [point.x for point in points]
|
||||||
|
y = [point.y for point in points]
|
||||||
|
|
||||||
|
plt.scatter(x, y)
|
||||||
|
|
||||||
|
# Plot a line from slope and intercept
|
||||||
|
axes = plt.gca()
|
||||||
|
x_vals = np.array(axes.get_xlim())
|
||||||
|
y_vals = intercept + slope * x_vals
|
||||||
|
|
||||||
|
for point in line_points:
|
||||||
|
plt.plot(point.x, point.y, 'go')
|
||||||
|
|
||||||
|
plt.plot(x_vals, y_vals, '--')
|
||||||
|
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
class Side(Enum):
|
||||||
|
ON = auto()
|
||||||
|
ABOVE = auto()
|
||||||
|
BELOW = auto()
|
||||||
|
|
||||||
|
|
||||||
|
def sidedness(slope: int, intersection: int, p3: Point, linprog_flipper: callable, eps=0.0000001) -> Side:
|
||||||
|
# finds where a point is in regards to a line
|
||||||
|
if linprog_flipper(p3.y) - eps <= linprog_flipper(slope * p3.x + intersection) <= linprog_flipper(p3.y) + eps:
|
||||||
|
return Side.ON
|
||||||
|
elif p3.y > slope * p3.x + intersection:
|
||||||
|
return Side.ABOVE
|
||||||
|
return Side.BELOW
|
||||||
|
|
||||||
|
|
||||||
|
def mbc_ch(points: Set[Point], linprog_flipper: callable) -> Set[Point]:
|
||||||
|
if len(points) <= 2:
|
||||||
|
return points
|
||||||
|
|
||||||
# Find the point with median x-coordinate, and partition the points on this point
|
# Find the point with median x-coordinate, and partition the points on this point
|
||||||
pm = statistics.median_high(points)
|
med_x = statistics.median(p.x for p in points)
|
||||||
|
|
||||||
pl = {point
|
# Find left and right points in regards to median
|
||||||
for point in points
|
pl = {p for p in points if p.x < med_x}
|
||||||
if point.x < pm.x}
|
pr = {p for p in points if p.x >= med_x}
|
||||||
|
|
||||||
pr = {point
|
|
||||||
for point in points
|
|
||||||
if point.x >= pm.x}
|
|
||||||
|
|
||||||
# Find the bridge over the vertical line in pm
|
# Find the bridge over the vertical line in pm
|
||||||
|
c = [linprog_flipper(med_x), linprog_flipper(1)]
|
||||||
|
A = [[linprog_flipper(-p.x), linprog_flipper(-1)] for p in points]
|
||||||
|
b = [linprog_flipper(-p.y) for p in points]
|
||||||
|
|
||||||
|
result = linprog(c, A, b, bounds=[(None, None), (None, None)], options={"tol": 0.00001})
|
||||||
|
slope, intercept = result.x[0], result.x[1]
|
||||||
|
|
||||||
|
# Find the two points which are on the line, should work
|
||||||
|
left_point = next(p for p in pl if sidedness(slope, intercept, p, linprog_flipper) == Side.ON)
|
||||||
|
right_point = next(p for p in pr if sidedness(slope, intercept, p, linprog_flipper) == Side.ON)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Prune the points between the two line points
|
||||||
|
pl = {p for p in pl if p.x <= left_point.x}
|
||||||
|
pr = {p for p in pr if p.x >= right_point.x}
|
||||||
|
|
||||||
|
return set.union(mbc_ch(pl, linprog_flipper), {left_point, right_point}, mbc_ch(pr, linprog_flipper))
|
||||||
|
|
||||||
|
|
||||||
|
points = {gen_point(1, 10) for _ in range(20)}
|
||||||
|
|
||||||
|
upper_hull_points = mbc_ch(points, lambda x: x)
|
||||||
|
lower_hull_points = mbc_ch(points, lambda x: -x)
|
||||||
|
|
||||||
|
display(points, upper_hull_points.union(lower_hull_points))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user