├── README.md ├── _init_.py ├── functions.py ├── setup.py └── test_problems.py /README.md: -------------------------------------------------------------------------------- 1 | # InverseProblem 2 | 3 | ip.optimalk(A) #this will print out optimal k 4 | 5 | ip.invert(A,be,k,l) #this will invert your A matrix, where be is noisy be, k is the no. of iterations, and lambda is your dampening effect (best set to 1) 6 | -------------------------------------------------------------------------------- /_init_.py: -------------------------------------------------------------------------------- 1 | 2 | def joke(): 3 | return (u'Actions demolish their alternatives. Experiments reveal them.') 4 | 5 | -------------------------------------------------------------------------------- /functions.py: -------------------------------------------------------------------------------- 1 | ''' 2 | define a function that takes a contaminated matrix, A, uses SVD to decompose it, and then gives the solution to Ax=b 3 | Requires matrix A, vector b, parameters k&l, 4 | 5 | ''' 6 | 7 | from __future__ import division #make / floating point division 8 | import numpy as np 9 | import pandas as pd 10 | import statsmodels.formula.api as smf 11 | import matplotlib.pyplot as plt 12 | import array 13 | import scipy 14 | from scipy import linalg 15 | 16 | 17 | #import this 18 | 19 | def invert(A, b, k, l): 20 | 21 | u, s, v = linalg.svd(A, full_matrices=False) #compute SVD without 0 singular values 22 | 23 | #number of `columns` in the solution s, or length of diagnol 24 | 25 | S = np.diag(s) 26 | sr, sc = S.shape #dimension of 27 | 28 | 29 | for i in range(0,sc-1): 30 | if S[i,i]>0.00001: 31 | S[i,i]=(1/S[i,i]) - (1/S[i,i])*(l/(l+S[i,i]**2))**k 32 | 33 | x1=np.dot(v.transpose(),S) #why traspose? because svd returns v.transpose() but we need v 34 | x2=np.dot(x1,u.transpose()) 35 | x3=np.dot(x2,b) 36 | 37 | return(u'This is the solution, X, to AX=b where A is ill-conditioned and b is noisy using a iterative Tikhonov regularization approach.', x3) 38 | 39 | 40 | 41 | #Elbow computes the elbow of a convex function 42 | def elbow(N): 43 | import numpy as np 44 | import matplotlib.pyplot as plt 45 | import array 46 | import scipy 47 | from scipy import linalg 48 | import matplotlib.pyplot as plt 49 | allCoord=N 50 | (nPoints,c)=allCoord.shape 51 | lastIndex=nPoints-1 52 | firstPoint=allCoord[0,:] 53 | lastPoint=allCoord[lastIndex,:] 54 | lineVec=np.subtract(lastPoint, firstPoint) #vector from first to last point 55 | lineVecN = [x / np.linalg.norm(lineVec)for x in lineVec] #divide by norm of lineVec to normalize 56 | lineVecN=np.array(lineVecN) 57 | vecFromFirst= np.subtract(allCoord,firstPoint) # vector between all points and first point 58 | vecFromFirstN=np.tile(lineVecN,(nPoints,1)) 59 | #vecFromFirstN=vecFromFirstN[0,:,:] 60 | scalarProduct=np.empty((nPoints,)) 61 | for i in range(nPoints): 62 | scalarProduct[i] = np.dot(vecFromFirst[i],vecFromFirstN[i]) 63 | vecFromFirstParallel=scalarProduct[:,None]*lineVecN 64 | #vecFromFirstParallel=vecFromFirstParallel[0,:,:] 65 | vecToLine= vecFromFirst- vecFromFirstParallel 66 | distToLine = np.apply_along_axis(np.linalg.norm, 1,vecToLine ) 67 | maxDist=np.amax(distToLine) 68 | ind = np.argmax(distToLine) 69 | plt.plot(allCoord[:,0],allCoord[:,1]) 70 | plt.hold(True) 71 | plt.plot([ind], [allCoord[ind,1]], 'g.', markersize=20.0) 72 | plt.show() 73 | return ind 74 | 75 | #A=np.matrix('1 3 11 0 -11 -15;18 55 209 15 -198 -277; -23 -33 144 532 259 82;9 55 405 437 -100 -285;3 -4 -111 -180 39 219;-13 -9 202 346 401 253') 76 | 77 | def optimalk(A): 78 | r, c = A.shape 79 | x0=np.zeros((c,1)) 80 | x=np.ones((c,1)) 81 | b =A*x 82 | nb = np.random.normal(0, .1, (r,1)) #add vector of normal variants mean=0,std=0.1 83 | be = b+nb #add noise 84 | u, s, v = linalg.svd(A, full_matrices=False) 85 | s = np.diag(s) 86 | l=1 87 | l1=.1 88 | k=200 89 | sr, sc = s.shape 90 | #S = csr_matrix(S) 91 | D=np.zeros((sr,k)) 92 | D1=np.zeros((sr,k)) 93 | N=np.zeros((k,sc)) 94 | N1=np.zeros((k,sc)) 95 | for j in range(0,k): 96 | S0=np.copy(s) #make a copy of s 97 | S1=np.copy(s) #make copy of s (not reference) 98 | for i in range(0,sc): 99 | S0[i,i]=(l/(l+S0[i,i]**2))**(j+1) 100 | S1[i,i]=(l1/(l1+S1[i,i]**2))**(j+1) 101 | x1=np.dot(S0,u.transpose()) 102 | x2=np.dot(x1,be) 103 | x2=np.reshape(x2,sr) 104 | D[:,j]=x2 105 | y1=np.dot(S1,u.transpose()) 106 | y2=np.dot(y1,be) 107 | y2=np.reshape(y2,sr) 108 | #y2=y2.ravel() #conver 2d to 1d 109 | D1[:,j]=y2 110 | N[j,1]=np.linalg.norm(D[:,j], ord=None, axis=None) 111 | N1[j,1]=np.linalg.norm(D1[:,j], ord=None, axis=None) 112 | N1[j,0]=j 113 | N[j,0]=j 114 | k=elbow(N) 115 | return('this is the optimal number of k iterations', k) 116 | 117 | 118 | 119 | Golub=np.matrix('1 3 11 0 -11 -15;18 55 209 15 -198 -277; -23 -33 144 532 259 82;9 55 405 437 -100 -285;3 -4 -111 -180 39 219;-13 -9 202 346 401 253') 120 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='InverseProblem', 4 | version='1.0', 5 | description='Iterative Approach to using Tikhonov Regularizaiton for inverting a matrix', 6 | url='http://github.com/kathrynthegreat/InverseProblem', 7 | author='Kathryn The Great', 8 | author_email='knv4@columbia.edu', 9 | license='Vasilaky', 10 | packages=['InverseProblem'], 11 | zip_safe=False) 12 | -------------------------------------------------------------------------------- /test_problems.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This script uses the InverseProblem package 3 | https://github.com/kathrynthegreat/InverseProblem 4 | https://pypi.python.org/pypi?%3Aaction=pkg_edit&name=InverseProblem 5 | 6 | InverseProblem.invert() is a function for the Generalized Tikhonov Problem uses a solution from an iterative ``plug and replug`` 7 | approach that passes by the noiseless solution. 8 | 9 | InverseProblem.invert() take three parameters A, the matrix, l, lambda the dampening factor, and k the iterations. 10 | 11 | ''' 12 | 13 | import numpy as np 14 | import pandas as pd 15 | import statsmodels.formula.api as smf 16 | import InverseProblem.functions as ip 17 | 18 | ##################### 19 | #Example 1 Perturb b, a slight change in the observed data 20 | ##################### 21 | A = np.matrix('.16, .10; .17 .11; 2.02 1.29') 22 | #A is ill-conditioned, 23 | np.linalg.cond(A) 24 | x=np.matrix('1;1') 25 | b=A*x #noise free right hand side 26 | 27 | #Now add noise to b of size ro 28 | # dimension of A 29 | r= np.matrix(A.shape)[0,0] 30 | #Introduce a slight perturbation to observed data 31 | nb= np.random.normal(0, .01, r) #compute vector of normal variants mean=0,std=0.1 32 | #You'll see that the data output is bad, high variance, so no solution is really good 33 | #nb= np.random.normal(0, 50, r) #compute vector of normal variants mean=0,std=50 34 | 35 | #note that nb is 3 by 1, so we need to flip it 36 | be=b+np.matrix(nb).transpose() #add noise 37 | 38 | l=1 39 | k=20 40 | 41 | ip.test() 42 | #Slight perturbation to b and the pseudo inverse sucks 43 | np.linalg.pinv(A)*be 44 | #Slight perturbation to b and the iterative approach rocks 45 | ip.invert(A,be,k,l) 46 | 47 | ##################### 48 | #Example 2 Perturb A 49 | ##################### 50 | #This example is meant to show that the pseudo inverse is an unstable solution 51 | #A is singular (deficient in rank). A_delta is almost singular. 52 | #The pseudo inverse solution is b=[1 0]. 53 | #When you perturb A slightly by one one millionth of a delta, the solution (x) change by a millionth fold 54 | #But when you use the iterative appraoch, the solution does not change by much 55 | # (Note: in this example we don't know the actual solution. We're just showing that Pseudo inverse sln is unstable) 56 | 57 | A = np.matrix('1, 0; 0 0; 0 0') 58 | A_delta = np.matrix('1, 0; 0 .00000001; 0 0') 59 | #condition number as being (very roughly) the rate at which the solution, x, will change with respect to a change in b. 60 | np.linalg.cond(A) 61 | np.linalg.cond(A_delta) 62 | b=np.matrix('1;1;1') #noise free right hand side 63 | 64 | 65 | l=.01 66 | k=100 67 | ip.invert(A_delta,b,k,l) 68 | np.linalg.pinv(A_delta)*b 69 | 70 | ##################### 71 | #Example 3 Hilbert A 72 | ##################### 73 | 74 | from scipy.linalg import hilbert 75 | A=hilbert(3) 76 | np.linalg.cond(A) 77 | x=np.matrix('1;1;1') 78 | b=A*x 79 | 80 | #Now add noise to b of size ro 81 | # dimension of A 82 | r= np.matrix(A.shape)[0,0] 83 | nb= np.random.normal(0, .50, r) #compute vector of normal variants mean=0,std=0.1 84 | #nb= np.random.normal(0, 50, r) #compute vector of normal variants mean=0,std=50 85 | #note that nb is 3 by 1, so we need to flip it 86 | be=b+np.matrix(nb).transpose() #add noise 87 | 88 | l=1 89 | k=100 90 | 91 | 92 | np.linalg.pinv(A)*be 93 | ip.invert(A,be,k,l) 94 | 95 | --------------------------------------------------------------------------------