def rbd(X, dmax, Er=0.01): """Decompose a matrix X using reduced basis decomposition. X = YT. Y basis vectors are constructed using mod_gramm_schmidt until an maximum basis number threshold (dmax) or an error requirement (Er) are satisfied.""" #Call start_state from the setup.py module to instantiate the parameters for the RBD X, Y, T, d, e_cur, i, used_i, complete = start_state(X) #Set the current_state to the initial parameters; subject to iterative change. current_state = [X, Y, T, d, e_cur, Er, i, used_i, complete] #While the requirements for the RBD have not been met... while d <= dmax and e_cur > Er and complete == False: #Orthogonally project the X[:,i] vector into Y, calling the mod_gramm_schmidt.py module. orthonormalization = mod_gramm_schmidt(*current_state) #mod_gramm_schmidt has a clause that signals complete to equal True. complete = orthonormalization[-1] #Break the while loop if mod_gramm_schmidt tells us the decomposition is complete. if complete == True: current_state = orthonormalization break else: #Prepare for the next round of orthonormalization by calling the find_error.py and check_error.py modules. current_state = check_error(*find_error(*orthonormalization)) #Update the active parameters, some of which govern the while loop. check_error() has a clause that signals completion. X, Y, T, d, e_cur, Er, i, used_i, complete = current_state #Final output of the function is a list of all the parameters. return current_state
def test_find_new_vector(): """Test that find_error returns new e_cur and i values. """ #Setup parameters test_image = mpimg.imread('images/DrawingHands.jpg') X, Y, T, d, e_cur, i, used_i, complete = start_state(test_image) Er = 0.0000000001 #Complete a full iteration of RBD d1_parameters = check_error(*find_error( *mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete))) #Take a snapshot of e_cur and i before running the find_error function e_cur_before_find_error = d1_parameters[4] i_before_find_error = d1_parameters[6] #Capture the results of find_error find_error_results = find_error(*mod_gramm_schmidt(*d1_parameters)) e_cur_after_find_error = find_error_results[4] i_after_find_error = find_error_results[6] used_i = find_error_results[7] #Assert that the new e_cur and i values returned by find_error are distinct. assert e_cur_before_find_error != e_cur_after_find_error assert i_before_find_error != i_after_find_error assert i_after_find_error not in used_i
def test_d1_not_done(): """Test mod_gramm_schmidt where d!=0 and there is a need to continue building the basis.""" #Setup parameters X, Y, T, d, e_cur, i, used_i, complete = start_state(test_image) Er = 0.0000000001 #Complete 1 round of the RBD decomposition algorithm d1_parameters = check_error(*find_error( *mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete))) #Apply gramm_schmidt at the beginning of stage d = 1 gramm_schmidt_results = mod_gramm_schmidt(*d1_parameters) #Update testing parameters X, Y, T, d, e_cur, Er, i, used_i, complete = gramm_schmidt_results #Test datatypes and values assert type(X) == np.ndarray assert type(Y) == np.ndarray assert type(T) == np.ndarray assert type(d) == int assert type(Er) == float assert type(used_i) == list assert complete == False #Assert that an orthogonal projection has been added to Y, and that a vector has been added to T. The dimensions of the dot product of Y and T should equal X. assert Y.shape[1] == T.shape[0] == 2 compression = np.dot(Y, T) assert compression.shape == X.shape #Definition of orthogonal matrix print("Y.T.dot(Y)", Y.T.dot(Y)) assert np.isclose(np.linalg.det(Y.T.dot(Y).astype(float)), 1)
def test_rbd_setup(): '''Test harness for the setup.py module''' test_image = mpimg.imread('images/DrawingHands.jpg') dmax = 40 X, Y, T, d, e_cur, i, used_i, complete = start_state(test_image) #Test datatypes and values assert type(X) == np.ndarray assert type(Y) == np.ndarray assert type(T) == np.ndarray assert type(d) == int assert type(e_cur) == float assert type(i) == int assert type(used_i) == list assert complete == False assert d < dmax #Test shapes assert Y.shape[0] == X.shape[0] assert Y.shape[1] == 1 assert T.shape[0] == 1 assert T.shape[1] == X.shape[1] assert len(used_i) == 0 assert d < dmax
def test_decomposition_complete(): """Test case for when e_cur <= Er, signaling that the decomposition is done.""" #Setup parameters X, Y, T, d, e_cur, i, used_i, complete = start_state(test_image) Er = np.inf #Capture results of RBD at the point before check_error is run. params_before_check_error = find_error( *mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete)) #Capture results after running check_error in a case that should return complete == True params_after_check_error = check_error(*params_before_check_error) #Test that check_error modifies complete to equal True. assert params_after_check_error[-1] == True != params_before_check_error[-1]
def test_decomposition_incomplete(): """Test case for check_error when the error requirement is not met. d increases to 1 for the next iteration of RBD.""" #Setup parameters X, Y, T, d, e_cur, i, used_i, complete = start_state(test_image) Er = 0.000000000000001 #Capture results of RBD at the point before check_error is run. params_before_check_error = find_error( *mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete)) #Capture results after running check_error in a case that should return complete == False params_after_check_error = check_error(*params_before_check_error) #Test that d is increased by 1 after check_error. d_before_check_error = params_before_check_error[3] d_after_check_error = params_after_check_error[3] assert d_before_check_error < d_after_check_error assert d_after_check_error - d_before_check_error == 1
def test_d1_done(): """Test mod_gramm_schmidt where d!=0 and the error requirement is met, ending the RBD algorithm.""" #Setup parameters X, Y, T, d, e_cur, i, used_i, complete = start_state(test_image) Er = 0.00001 #Complete 1 round of the RBD decomposition algorithm and update parameters. d1_parameters = check_error(*find_error( *mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete))) X, Y, T, d, e_cur, Er, i, used_i, complete = d1_parameters #print("d: ",d) #print("Y: ", Y) #Ensure that the algorithm will think the decomposition is complete. Er = 50000 #Apply gramm_schmidt at the beginning of stage d = 1 gramm_schmidt_results = mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete) assert gramm_schmidt_results[-1] == True
def test_d0(): """Test the first iteration of mod_gramm_schmidt where d == 0""" #Setup parameters X, Y, T, d, e_cur, i, used_i, complete = start_state(test_image) Er = 0.0000000001 #Apply gramm_schmidt gramm_schmidt_results = mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete) #Update testing parameters X, Y, T, d, e_cur, Er, i, used_i, complete = gramm_schmidt_results #Test datatypes and values assert type(X) == np.ndarray assert type(Y) == np.ndarray assert type(T) == np.ndarray assert type(d) == int assert type(Er) == float assert type(i) == int assert type(used_i) == list assert complete == False #Test that Y and T have non-zero basis assert np.count_nonzero(Y) > 0 assert np.count_nonzero(T) > 0 #Test that Y and T have the right shapes. assert Y.shape[1] == 1 assert Y.shape[0] == X.shape[0] assert T.shape[1] == X.shape[1] assert T.shape[0] == 1 #Assert that an index has been added to used_i""" assert len(used_i) == 1
return decomposition #If the error requirement has not been met, normalize u_d and add it to Y as a column vector. Add the dot product of u_d.transpose and X to T else: basis_vector = np.divide(u_d, np.linalg.norm(u_d)) Y = np.column_stack((Y, basis_vector)) T = np.row_stack((T, np.dot(Y[:, d].T, X))) used_i.append(i) #Return updated parameters, leading to the find_error process of the algorithm. update_state = (X, Y, T, d, e_cur, Er, i, used_i, complete) return update_state if __name__ == '__main__': from setup import start_state alist = np.array([[1, 1, 0, 1, 0], [1, 0, 1, 1, 0], [0, 1, 1, 1, 0]]) X, Y, T, d, e_cur, i, used_i, complete = start_state(alist) Er = 0.000001 test_results = mod_gramm_schmidt(X, Y, T, d, e_cur, Er, i, used_i, complete) X, Y, T, d, e_cur, Er, i, used_i, complete = test_results def display_state(attributes): names = ['X', 'Y', 'U', 'd', 'e_cur', 'Er', 'i', 'used_i', 'complete'] for i in range(len(names)): print("\n\n", names[i], " :\n", attributes[i])