Group people which have different locations - pandas

I need help. My function to group people does not really work. The problem is quite simple:
I have a dataframe with following columns:
latitude
longitude
floor
These columns are random locations of people.
The dataframe has a length of multiple of 9 (in this example the length is 36. I reality it is much longer).
I want to group people by the following idea:
First I create a new column with the name "group".
People who live close together (according to coordinates) are assigned to a specific group number (1, 2 3,...). Each group contains 3 people.
Now the tricky part: People with identical coordinates can not be in the same group!
This is how I did it:
Here is the data:
array_data=([[ 50.56419 , 8.67667 , 2. , 160. ],
[ 50.5643136, 8.6772816, 3. , 89. ],
[ 50.5646274, 8.6763909, 0. , 259. ],
[ 50.5661047, 8.6765931, 1. , 100. ],
[ 50.5663442, 8.6575205, 1. , 117. ],
[ 50.56686 , 8.67598 , 1. , 95. ],
[ 50.56747 , 8.67604 , 2. , 199. ],
[ 50.56762 , 8.6702799, 0. , 148. ],
[ 50.5693473, 8.6640855, -1. , 50. ],
[ 50.5693473, 8.6640855, 0. , 111. ],
[ 50.5705819, 8.6597279, 2. , 183. ],
[ 50.57067 , 8.65694 , 2. , 257. ],
[ 50.57075 , 8.65748 , 1. , 211. ],
[ 50.57075 , 8.65748 , 1. , 292. ],
[ 50.5722461, 8.6598248, 2. , 142. ],
[ 50.57254 , 8.65895 , 1. , 116. ],
[ 50.57259 , 8.6592 , 2. , 228. ],
[ 50.5731636, 8.667609 , 1. , 181. ],
[ 50.5737814, 8.6720067, 0. , 173. ],
[ 50.5740356, 8.6718179, 1. , 5. ],
[ 50.5746321, 8.6831284, 3. , 202. ],
[ 50.5747453, 8.6765588, 4. , 119. ],
[ 50.5748992, 8.6611471, 2. , 260. ],
[ 50.5748992, 8.6611471, 3. , 102. ],
[ 50.575 , 8.65985 , 2. , 267. ],
[ 50.5751 , 8.66027 , 2. , 7. ],
[ 50.5751 , 8.66027 , 2. , 56. ],
[ 50.57536 , 8.67741 , 1. , 194. ],
[ 50.57536 , 8.67741 , 1. , 282. ],
[ 50.5755255, 8.6884584, 0. , 276. ],
[ 50.5755273, 8.674282 , 3. , 167. ],
[ 50.57553 , 8.6826 , 2. , 273. ],
[ 50.5755973, 8.6847492, 0. , 168. ],
[ 50.5756757, 8.6846139, 4. , 255. ],
[ 50.57572 , 8.65965 , 0. , 66. ],
[ 50.57591 , 8.68175 , 1. , 187. ]])
Convert array to dataframe and rename the columns:
df = pd.DataFrame(data=array_data) # convert back to dataframe
df.rename(columns={0: 'latitude', 1: 'longitude', 2:'floor', 3:'id'}, inplace=True) # rename columns
Now we have the dataframe. With the following functions I was trying to group the people:
First we need to find a way, to get the distances to the people:
def calculate_distance(lat1, lon1, lat2, lon2):
"""
Calculate the shortest distance between two points given by the latitude and
longitude.
"""
earth_radius = 6373 # Approximate / in km.
lat1 = radians(lat1)
lon1 = radians(lon1)
lat2 = radians(lat2)
lon2 = radians(lon2)
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
return earth_radius * c # in km.
And here is the main function. I try to group people if they have NOT the same location:
def sort_people(all_persons, max_distance_parameter):
'''
People in the same group have different location!
'''
assert len(all_persons) % 9 == 0
all_persons.set_index("id", drop=False, inplace=True)
all_persons["host"] = np.nan
all_persons["group"] = np.nan
scattering_factor= 0.0001 # to seperate same floor numbers
max_distance = max_distance_parameter
group_number = 0
group = []
for _, candidate in all_persons.iterrows():
if len(group) == 3:
for person in group:
all_persons.at[person["id"], "group"] = group_number
group_number += 1
group = []
if len(group) == 0:
group.append(candidate)
else:
for person in group:
distance = calculate_distance(
candidate["latitude"],
candidate["longitude"],
person["latitude"],
person["longitude"],
)
distance = distance
if candidate['floor'] == -1: # consider the floor when calculating the distance
distance = distance + scattering_factor + 0.001
elif candidate['floor'] == 0:
distance = distance + scattering_factor + 0.002
elif candidate['floor'] == 1:
distance = distance + scattering_factor + 0.003
elif candidate['floor'] == 2:
distance = distance + scattering_factor + 0.004
elif candidate['floor'] == 3:
distance = distance + scattering_factor + 0.005
elif candidate['floor'] == 4:
distance = distance + scattering_factor + 0.006
elif candidate['floor'] == 5:
distance = distance + scattering_factor + 0.007
elif candidate['floor'] == 6:
distance = distance + scattering_factor + 0.008
elif candidate['floor'] == 7:
distance = distance + scattering_factor + 0.009
elif candidate['floor'] == 8:
distance = distance + scattering_factor + 0.010
elif candidate['floor'] == 9:
distance = distance + scattering_factor + 0.011
elif candidate['floor'] == 10:
distance = distance + scattering_factor + 0.012
elif candidate['floor'] == 11:
distance = distance + scattering_factor + 0.013
elif candidate['floor'] == 12:
distance = distance + scattering_factor + 0.014
elif candidate['floor'] == 13:
distance = distance + scattering_factor + 0.015
elif candidate['floor'] == 14:
distance = distance + scattering_factor + 0.016
else:
distance = distance + scattering_factor + 0.017
if 0 < distance <= max_distance:
group.append(candidate)
break
Long story short: this doesn't really work. At the end, I get a dataframe and I find people in the same locations which are assigned to the same group. How would you do it?

Using your solution, add logic to see if the person with same coordinates is already in the group. When you check if the group has no people, add. But if there is a person in the group, for each person in the group calculate the distance between that person and the candidate. If it is 0, then break(exit and don't add the person to that group). Then go to next group and do the same.
Btw. I'm not familiar with this programming language so I might've written bad syntax, so please use the above pseudocode to be a guide. Cheers!
if len(group) == 0:
group.append(candidate)
else:
for person in group:
distance = calculate_distance(
candidate["latitude"],
candidate["longitude"],
person["latitude"],
person["longitude"],
)
distance = distance
**if distance == 0 : break;**
if candidate['floor'] == -1: # consider the floor when calculating the distance
distance = distance + scattering_factor + 0.001
elif candidate['floor'] == 0:
distance = distance + scattering_factor + 0.002
elif candidate['floor'] == 1:
distance = distance + scattering_factor + 0.003
elif candidate['floor'] == 2:
distance = distance + scattering_factor + 0.004
elif candidate['floor'] == 3:
distance = distance + scattering_factor + 0.005
elif candidate['floor'] == 4:
distance = distance + scattering_factor + 0.006
elif candidate['floor'] == 5:
distance = distance + scattering_factor + 0.007
elif candidate['floor'] == 6:
distance = distance + scattering_factor + 0.008
elif candidate['floor'] == 7:
distance = distance + scattering_factor + 0.009
elif candidate['floor'] == 8:
distance = distance + scattering_factor + 0.010
elif candidate['floor'] == 9:
distance = distance + scattering_factor + 0.011
elif candidate['floor'] == 10:
distance = distance + scattering_factor + 0.012
elif candidate['floor'] == 11:
distance = distance + scattering_factor + 0.013
elif candidate['floor'] == 12:
distance = distance + scattering_factor + 0.014
elif candidate['floor'] == 13:
distance = distance + scattering_factor + 0.015
elif candidate['floor'] == 14:
distance = distance + scattering_factor + 0.016
else:
distance = distance + scattering_factor + 0.017
if 0 < distance <= max_distance:
group.append(candidate)
break

Related

Pi Pico Micropython Loop seems to get stuck

I am using a Pico as part of my dissertation along with an Arduino Due for a low cost fully autonomous UAV.
Anyway to the point, the code was working before I added the GPS part but now even if I take it out the ultrasonics won't work correctly. only shows the left sensor and doesn't continue on to the GPS.
I was also trying to use the multithreader with no joy :(
Any help or suggestions would be great.
Its a bit messy I know not quite got round to polishing it.
from machine import Pin
import utime, _thread, machine
import os
from rp2 import PIO, StateMachine, asm_pio
#print sys info
print(os.uname())
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0) # onboard LED OFF for 0.5 sec
utime.sleep(0.5)
led_onboard.value(1)
uart = machine.UART(0, baudrate=9600)
ser = machine.UART(1, baudrate=9600)
print(uart)
print(ser)
baton = _thread.allocate_lock()
rcvChar = b""
trigger = Pin(3, Pin.OUT) #left
echo = Pin(2, Pin.IN)
trigger2 = Pin(6, Pin.OUT) #right
echo2 = Pin(7, Pin.IN)
trigger4 = Pin(9, Pin.OUT) #backward
echo4 = Pin(8, Pin.IN)
def decode(coord):
#Converts DDDMM.MMMMM > DD deg MM.MMMMM min
x = coord.split(".")
head = x[0]
tail = x[1]
deg = head[0:-2]
min = head[-2:]
return deg + " deg " + min + "." + tail + " min"
def ultraleft():
trigger.low()
utime.sleep_us(2)
trigger.high()
utime.sleep_us(5)
trigger.low()
while echo.value() == 0:
signaloff = utime.ticks_us()
while echo.value() == 1:
signalon = utime.ticks_us()
timepassed = signalon - signaloff
Ldistance = (timepassed * 0.0343) / 2
utime.sleep(0.1)
trigger.low()
utime.sleep_us(2)
trigger.high()
utime.sleep_us(5)
trigger.low()
while echo.value() == 0:
signaloff = utime.ticks_us()
while echo.value() == 1:
signalon = utime.ticks_us()
timepassed = signalon - signaloff
Ldistance2 = (timepassed * 0.0343) / 2
newLdist = (Ldistance + Ldistance2) / 2
if newLdist > 120:
newLdist = 120
elif newLdist <= 100:
print("Distance Left less than 100")
return True
print("The distance Left from object is ",newLdist,"cm")
def ultraright():
trigger2.low()
utime.sleep_us(2)
trigger2.high()
utime.sleep_us(5)
trigger2.low()
while echo2.value() == 0:
signaloff2 = utime.ticks_us()
while echo2.value() == 1:
signalon2 = utime.ticks_us()
timepassed2 = signalon2 - signaloff2
Rdistance = (timepassed2 * 0.0343) / 2
utime.sleep(0.1)
trigger2.low()
utime.sleep_us(2)
trigger2.high()
utime.sleep_us(5)
trigger2.low()
while echo2.value() == 0:
signaloff2 = utime.ticks_us()
while echo2.value() == 1:
signalon2 = utime.ticks_us()
timepassed2 = signalon2 - signaloff2
Rdistance2 = (timepassed2 * 0.0343) / 2
newRdist = (Rdistance + Rdistance2) / 2
if newRdist > 120:
newRdist = 120
elif newRdist <= 100:
print("Distance Right less than 100")
return True
print("The distance Right from object is ",newRdist,"cm")
def ultradwn():
trigger4.low()
utime.sleep_us(2)
trigger4.high()
utime.sleep_us(5)
trigger4.low()
while echo4.value() == 0:
signaloff4 = utime.ticks_us()
while echo4.value() == 1:
signalon4 = utime.ticks_us()
timepassed4 = signalon4 - signaloff4
Ddistance = (timepassed4 * 0.0343) / 2
utime.sleep(0.1)
trigger4.low()
utime.sleep_us(2)
trigger4.high()
utime.sleep_us(5)
trigger4.low()
while echo4.value() == 0:
signaloff4 = utime.ticks_us()
while echo4.value() == 1:
signalon4 = utime.ticks_us()
timepassed4 = signalon4 - signaloff4
Ddistance2 = (timepassed4 * 0.0343) / 2
newDdist = (Ddistance + Ddistance2) / 2
if newDdist > 120:
newDdist = 120
elif newDdist >20 :
print("Distance Down is greater than 20")
x = 1
#uart.write("D20")
#uart.write("\n")
#print("Sent TO Height")
return True
elif newDdist <12 :
print("Distance Down is less than 12")
x = 2
#uart.write("D12")
#uart.write("\n")
#print("Sent Landed")
return True
print("The distance Down from object is ",newDdist,"cm")
def gps():
while True:
#baton.acquire()
rcvChar = ser.readline()
gps_data =rcvChar.decode("ASCII")
data = gps_data
if (data[0:6] == "$GPRMC"):
sdata = data.split(",")
if (sdata[2] == 'V'):
print("no satellite data available")
print ("---Parsing GPRMC---")
time = sdata[1][0:2] + ":" + sdata[1][2:4] + ":" + sdata[1][4:6]
lat = decode(sdata[3]) #latitude
dirLat = sdata[4] #latitude direction N/S
lon = decode(sdata[5]) #longitute
dirLon = sdata[6] #longitude direction E/W
speed = sdata[7] #Speed in knots
trCourse = sdata[8] #True course
date = sdata[9][0:2] + "/" + sdata[9][2:4] + "/" + sdata[9][4:6]#date
print ("time : %s, latitude : %s(%s), longitude : %s(%s), speed : %s, True Course : %s, Date : %s" % (time,lat,dirLat,lon,dirLon,speed,trCourse,date))
#baton.acquire()
#_thread.start_new_thread(gps(), ())
while True:
x = 0
#baton.acquire()
ultraleft()
utime.sleep(0.1)
ultraright()
utime.sleep(0.1)
ultradwn()
utime.sleep(0.1)
if ultraleft():
uart.write("LO")
uart.write("\n")
print("Sent Left")
utime.sleep(1)
if ultraright():
uart.write("RO")
uart.write("\n")
print("Sent Right")
uart.sendbreak()
utime.sleep(1)
if ultradwn():
if x == 1:
uart.write("D20")
uart.write("\n")
print("Sent TO Height")
utime.sleep(1)
if x == 2:
uart.write("D12")
uart.write("\n")
print("Sent Landed")
utime.sleep(1)
utime.sleep(1)
gps()
#baton.release()

Minimum number of jumps to reach end dynamic programmig

Given an array, verify from the first element how many steps are needed to reach the end.
Example: arr = [1, 3, 5, 8, 4, 2, 6, 7, 0, 7, 9]
1 -> 3 -> 8 (this is the shortest path)
3 steps.
So far, i have this code from geeks for geeks:
def jumpCount(x, n):
jumps = [0 for i in range(n)]
if (n == 0) or (x[0] == 0):
return float('inf')
jumps[0] = 0
for i in range(1, n):
jumps[i] = float('inf')
for j in range(i):
if (i <= j + x[j]) and (jumps[j] != float('inf')):
jumps[i] = min(jumps[i], jumps[j] + 1)
break
return jumps[n-1]
def jumps(x):
n = len(x)
return jumpCount(x,n)
x = [1, 3, 5, 8, 4, 2, 6, 7, 0, 7, 9]
print(jumps(x))
But I want to print out what numbers made the shortest path (1-3-8). How can I adapt the code to do it?
I tried to create a list of j's but since 5 is tested in the loop, it's appended too.
Link to the problem:
https://www.geeksforgeeks.org/minimum-number-of-jumps-to-reach-end-of-a-given-array/
The essential idea is that you need an auxiliary structure to help you keep track of the minimum path. Those type of structures are usually called "backpointers" (you could call them in our case "forwardpointers" since we are going forward, duh). My code solves the problem recursively, but the same could be done iteratively. The strategy is as follows:
jumps_vector = [ 1, 3, 5, 8, 4, 2, 6, 7, 0, 7, 9 ]
"""
fwdpointers holds the relative jump size to reach the minimum number of jumps
for every component of the original vector
"""
fwdpointers = {}
def jumps( start ):
if start == len( jumps_vector ) - 1:
# Reached the end
return 0
if start > len( jumps_vector ) - 1:
# Cannot go through that path
return math.inf
if jumps_vector[ start ] == 0:
# Cannot go through that path (infinite loop with itself)
return math.inf
# Get the minimum in a traditional way
current_min = jumps( start + 1 )
fwdpointers[ start ] = start + 1
for i in range( 2, jumps_vector[ start ] + 1 ):
aux_min = jumps( start + i )
if current_min > aux_min:
# Better path. Update minimum and fwdpointers
current_min = aux_min
# Store the (relative!) index of where I jump to
fwdpointers[ start ] = i
return 1 + current_min
In this case, the variable fwdpointers stores the relative indexes of where I jump to. For instance, fwdpointers[ 0 ] = 1, since I will jump to the adjacent number, but fwdpointers[ 1 ] = 2 since I will jump two numbers the next jump.
Having done that, then it's only a matter of postprocessing things a bit on the main() function:
if __name__ == "__main__":
min_jumps = jumps( 0 )
print( min_jumps )
# Holds the index of the jump given such that
# the sequence of jumps are the minimum
i = 0
# Remember that the contents of fwdpointers[ i ] are the relative indexes
# of the jump, not the absolute ones
print( fwdpointers[ 0 ] )
while i in fwdpointers and i + fwdpointers[ i ] < len( jumps_vector ):
print( jumps_vector[ i + fwdpointers[ i ] ] )
# Get the index of where I jump to
i += fwdpointers[ i ]
jumped_to = jumps_vector[ i ]
I hope this answered your question.
EDIT: I think the iterative version is more readable:
results = {}
backpointers = {}
def jumps_iter():
results[ 0 ] = 0
backpointers[ 0 ] = -1
for i in range( len( jumps_vector ) ):
for j in range( 1, jumps_vector[ i ] + 1 ):
if ( i + j ) in results:
results[ i + j ] = min( results[ i ] + 1, results[ i + j ] )
if results[ i + j ] == results[ i ] + 1:
# Update where I come from
backpointers[ i + j ] = i
elif i + j < len( jumps_vector ):
results[ i + j ] = results[ i ] + 1
# Set where I come from
backpointers[ i + j ] = i
return results[ len( jumps_vector ) - 1 ]
And the postprocessing:
i = len( jumps_vector ) - 1
print( jumps_vector[ len( jumps_vector ) - 1 ], end = " " )
while backpointers[ i ] >= 0:
print( jumps_vector[ backpointers[ i ] ], end = " " )
i = backpointers[ i ]
print()

Get corner of rectangle near to origin in batch of tensor given any two diagonal coordinates in pytorch

Let's say I have pytorch tensor of batch of coordinates of off diagonal elements and I want to get coordinate of the corner which is near to origin. coordinates are in (x1, y1, x2, y2) form.
a = torch.tensor([[3,2,2,3], [1,1,2,2])
# expected output
[[2,2], [1,1]]
You can just iterate over all tensors and for each of them calculate distance to four corners and take the corner with minimum distance.
import torch
a = torch.tensor([[3,2,2,3], [1,1,2,2]])
c = torch.zeros(a.shape[0], 2)
for idx, x in enumerate(a):
d1 = x[0] ** 2 + x[1] ** 2
d2 = x[2] ** 2 + x[3] ** 2
d3 = x[0] ** 2 + x[3] ** 2
d4 = x[2] ** 2 + x[1] ** 2
dmin = min(d1, d2, d3, d4)
if d1 == dmin:
c[idx] = torch.tensor([x[0], x[1]])
elif d2 == dmin:
c[idx] = torch.tensor([x[2], x[3]])
elif d3 == dmin:
c[idx] = torch.tensor([x[0], x[3]])
elif d4 == dmin:
c[idx] = torch.tensor([x[2], x[1]])
print(c) # tensor([[2., 2.], [1., 1.]])

Multiplying a specific cell value based on if statement in a Pandas dataframe

So I am trying to associate a specific value ('Property Damage') with every row in my dataset but I am having some trouble with this. Specifically, I want to multiply the value in the 'MD' column for each row by a number (0.02, 0.15, etc.) if it meets the conditions specified in the for loop (e.g. if i >= 0.8062, print etc.). I have included my code below:
df['RAND'] = np.random.uniform(0, 1, size=df.index.size)
dfRAND = list(df['RAND'])
def sim_1():
for i in dfRAND:
result = []
if i >= 0.8062:
df['Property Damage'] = df['MD'].apply(lambda x: x * 0.02)
print(list(val for x, val in enumerate(df['Count']) if
x == dfRAND.index(i)), 'LF0', i,':', df['Property Damage'])
elif 0.01 <= i < 0.89062:
df['Property Damage'] = list(df['MD'].apply(lambda x: x * 0.15))
print(list(val for x, val in enumerate(df['Count']) if
x == dfRAND.index(i)),'LF1', i, ':', df['Property Damage'])
elif 0.05 <= i < 0.01:
df['Property Damage'] = list(df['MD'].apply(lambda x: x * 0.20))
print(list(val for x, val in enumerate(df['Count']) if
x == dfRAND.index(i)),'LF2', i,':', df['Property Damage'])
elif 0.025 <= i < 0.05:
df['Property Damage'] = list(df['MD'].apply(lambda x: x * 0.50))
print(list(val for x, val in enumerate(df['Count']) if
x == dfRAND.index(i)),'LF3', i,':', df['Property Damage'])
elif 0.0125 <= i < 0.025:
df['Property Damage'] = list(df['MD'].apply(lambda x: x * 1))
print(list(val for x, val in enumerate(df['Count']) if
x == dfRAND.index(i)),'LF4', i,':', df['Property Damage'])
elif 0.0063 <= i < 0.0125:
df['Property Damage'] = list(df['MD'].apply(lambda x: x * 1))
print(list(val for x, val in enumerate(df['Count']) if
x == dfRAND.index(i)),'LF5', i,':', df['Property Damage'])
The problem I am having at the moment is that the code prints all the 'Property Damage' values for each row. I want it to give me the 'Property Damage' value for a specific row based on whichever condition is met in the for loop.
Any help is appreciated. Thanks in advance.
Are you looking for something like this?
my_bins = {pd.Series.max(df['RAND'])-1: 1,
.01: .15,
.0125: 1,
.025: .5,
.05: .2,
pd.Series.max(df['RAND'])+1 : .02}
df['rand_multiplier'] = pd.cut(df['RAND'], bins = sorted(my_bins.keys()), labels = list(range(len(my_bins) - 1))).apply(lambda x: my_bins[sorted(my_bins.keys())[x]])
df.apply(lambda row: row['MD'] * row['rand_multiplier'], axis = 1)
I'm in a bit of a hurry so it's not the prettiest thing. Basically I created bins based on the criteria you had and created a "multiplier" column which associates each entry in df['RAND'] with a multiplying factor. Then we can iterate over df and apply the multiplying factor to your 'MD' row.
Of course, I can't show the produced results without the 'MD' data.

Find control point on piecewise quadratic Bezier curve

I need to write a program to generate and display a piecewise quadratic Bezier curve that interpolates each set of data points (I have a txt file contains data points). The curve should have continuous tangent directions, the tangent direction at each data point being a convex combination of the two adjacent chord directions.
0.1 0,
0 0,
0 5,
0.25 5,
0.25 0,
5 0,
5 5,
10 5,
10 0,
9.5 0
The above are the data points I have, does anyone know what formula I can use to calculate control points?
You will need to go with a cubic Bezier to nicely handle multiple slope changes such as occurs in your data set. With quadratic Beziers there is only one control point between data points and so each curve segment much be all on one side of the connecting line segment.
Hard to explain, so here's a quick sketch of your data (black points) and quadratic control points (red) and the curve (blue). (Pretend the curve is smooth!)
Look into Cubic Hermite curves for a general solution.
From here: http://blog.mackerron.com/2011/01/01/javascript-cubic-splines/
To produce interpolated curves like these:
You can use this coffee-script class (which compiles to javascript)
class MonotonicCubicSpline
# by George MacKerron, mackerron.com
# adapted from:
# http://sourceforge.net/mailarchive/forum.php?thread_name=
# EC90C5C6-C982-4F49-8D46-A64F270C5247%40gmail.com&forum_name=matplotlib-users
# (easier to read at http://old.nabble.com/%22Piecewise-Cubic-Hermite-Interpolating-
# Polynomial%22-in-python-td25204843.html)
# with help from:
# F N Fritsch & R E Carlson (1980) 'Monotone Piecewise Cubic Interpolation',
# SIAM Journal of Numerical Analysis 17(2), 238 - 246.
# http://en.wikipedia.org/wiki/Monotone_cubic_interpolation
# http://en.wikipedia.org/wiki/Cubic_Hermite_spline
constructor: (x, y) ->
n = x.length
delta = []; m = []; alpha = []; beta = []; dist = []; tau = []
for i in [0...(n - 1)]
delta[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i])
m[i] = (delta[i - 1] + delta[i]) / 2 if i > 0
m[0] = delta[0]
m[n - 1] = delta[n - 2]
to_fix = []
for i in [0...(n - 1)]
to_fix.push(i) if delta[i] == 0
for i in to_fix
m[i] = m[i + 1] = 0
for i in [0...(n - 1)]
alpha[i] = m[i] / delta[i]
beta[i] = m[i + 1] / delta[i]
dist[i] = Math.pow(alpha[i], 2) + Math.pow(beta[i], 2)
tau[i] = 3 / Math.sqrt(dist[i])
to_fix = []
for i in [0...(n - 1)]
to_fix.push(i) if dist[i] > 9
for i in to_fix
m[i] = tau[i] * alpha[i] * delta[i]
m[i + 1] = tau[i] * beta[i] * delta[i]
#x = x[0...n] # copy
#y = y[0...n] # copy
#m = m
interpolate: (x) ->
for i in [(#x.length - 2)..0]
break if #x[i] <= x
h = #x[i + 1] - #x[i]
t = (x - #x[i]) / h
t2 = Math.pow(t, 2)
t3 = Math.pow(t, 3)
h00 = 2 * t3 - 3 * t2 + 1
h10 = t3 - 2 * t2 + t
h01 = -2 * t3 + 3 * t2
h11 = t3 - t2
y = h00 * #y[i] +
h10 * h * #m[i] +
h01 * #y[i + 1] +
h11 * h * #m[i + 1]
y