├── README.md └── fif.py /README.md: -------------------------------------------------------------------------------- 1 | fractal_interpolation 2 | ===================== 3 | 4 | This implements a technique for curve fitting by fractal interpolation found in a paper by Manousopoulos, Drakopoulos, and Theoharis, found [here](http://graphics.di.uoa.gr/Downloads/papers/journals/p30.pdf). I also used infromation about non-linear fractal interpolating functions found [here](http://www.mi.sanu.ac.rs/vismath/kobes/). 5 | 6 | 7 | Usage 8 | ===== 9 | 10 | Here, `U` is the original data. **Line 5** "fractalizes" example data, and **line 6** performs the interpolation. 11 | 12 | u = np.array([0.0,0.4,0.7,1.0]) 13 | v = np.array([0.0,0.5,0.2,0.0]) 14 | 15 | U = np.vstack((u,v)).T 16 | U = G( U, 0.1, balance=0 ) 17 | X = FIF( U, 0.01, balance=1 ) 18 | 19 | plot( U[:,0], U[:,1], '.-' ) 20 | plot( X[:,0], X[:,1], '.-' ) 21 | -------------------------------------------------------------------------------- /fif.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy, random 3 | 4 | def d( x ): 5 | # expects an enumerable, subtracts the right endpoint from the left 6 | return float(x[-1]-x[0]) 7 | 8 | 9 | def an( x, i ): 10 | # the (0,0) element in the rotation matrix of the iterated function system (IFS) 11 | return ( x[i] - x[i-1] )/d(x) 12 | 13 | 14 | def dn( x, i ): 15 | # the (0) element in the translation vector of the IFS 16 | return ( x[i-1] - 0*x[i] )/d(x) 17 | 18 | 19 | def cn( x, y, i, sn ): 20 | # the (1,0) element in the rotation matrix of the IFS 21 | return ( y[i] - y[i-1] )/d(x) - sn*( y[-1] - y[0] )/d(x) 22 | 23 | 24 | def en( x, y, i, sn ): 25 | # the (1) element in the translation vector of the IFS 26 | return ( x[-1]*y[i-1] - x[0]*y[i])/d(x) - sn*( x[-1]+y[0] - x[0]*y[-1] )/d(x) 27 | 28 | def Wn( X, U, i, sn ): 29 | ''' 30 | the iterated function sytem 31 | R is the rotation matrix 32 | T is the translation vector 33 | computes 34 | R*X + T 35 | ''' 36 | # rotation matrix 37 | R = np.matrix([[ an(U[:,0],i), 0 ],\ 38 | [ cn(U[:,0],U[:,1],i,sn), sn ]]) 39 | # transalation vector 40 | T = np.matrix([[ dn(U[:,0],i) ],\ 41 | [ en(U[:,0],U[:,1],i,sn) ]]) 42 | # calculate R*X + T 43 | tmp = R * np.matrix(X).T + T 44 | # return the new points 45 | xp, yp = np.array( tmp.T )[0] 46 | return xp, yp 47 | 48 | def T( U, X, deterministic=True ): 49 | ''' 50 | final transformation that converts points from the 51 | attractor to points that interpolate the data 52 | ''' 53 | M = U.shape[0] 54 | N = X.shape[0] 55 | if M % 2 == 0: 56 | s = M - 1 57 | else: 58 | s = M - 2 59 | u, v = list(), list() 60 | # interpolates between each two points 61 | for i in range( 1, M ): 62 | if deterministic: 63 | x_prime = np.median( X[(i-1)*s:(i)*s,0] ) 64 | y_prime = np.median( X[(i-1)*s:(i)*s,1] ) 65 | else: 66 | x_prime = random.choice( X[(i-1)*s:(i)*s,0] ) 67 | y_prime = random.choice( X[(i-1)*s:(i)*s,1] ) 68 | dU = U[i,0]-U[i-1,0] 69 | dX = X[(i)*s,0] - X[(i-1)*s,0] 70 | u.append( U[i-1,0] + dU*( x_prime - X[(i-1)*s,0] ) / dX ) 71 | v.append( y_prime ) 72 | X = np.vstack((u,v)).T 73 | X = np.vstack((U,X)) 74 | X = X[ X[:,0].argsort() ] 75 | return X 76 | 77 | def G( U, sn, balance=False ): 78 | # the fractal interpolating function 79 | X = U.copy() 80 | x, y = list( X[:,0] ), list( X[:,1] ) 81 | M = U.shape[0] 82 | N = X.shape[0] 83 | # for each data point.. 84 | for i in range(N): 85 | # call an IFS for each segment 86 | for j in range( 1,M ): 87 | xp, yp = Wn( X[i], U, j, sn ) 88 | x.append( xp ) 89 | y.append( yp ) 90 | if balance: 91 | xp, yp = Wn( X[i], U, j, -sn ) 92 | x.append( xp ) 93 | y.append( yp ) 94 | x = np.array(x) 95 | y = np.array(y) 96 | # this puts the interpolated 97 | # data points at the bottom of X 98 | X = np.vstack((x,y)).T 99 | X = X[ X[:,0].argsort() ] 100 | # these two lines rearrage X so that the interpolated 101 | # data points are between the original data points 102 | null, indices = np.unique( X[:,0], return_index=True ) 103 | X = X[ indices ] 104 | return X 105 | 106 | def FIF( U, sn, balance=False, deterministic=True ): 107 | # create attractor 108 | X = G( U, sn, balance ) 109 | # form interpolation 110 | X = T( U, X, deterministic ) 111 | return X 112 | --------------------------------------------------------------------------------