From 52ee9a1e128c137793f08f69f4835b67f3b9c5d1 Mon Sep 17 00:00:00 2001 From: Stephen Lee <245885195@qq.com> Date: Fri, 22 Sep 2017 14:34:28 +0800 Subject: [PATCH 01/29] commit convolution_neural_network.py --- Neural_Network/convolution_neural_network.py | 343 +++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 Neural_Network/convolution_neural_network.py diff --git a/Neural_Network/convolution_neural_network.py b/Neural_Network/convolution_neural_network.py new file mode 100644 index 000000000..539c315a0 --- /dev/null +++ b/Neural_Network/convolution_neural_network.py @@ -0,0 +1,343 @@ +#-*- coding: utf-8 -*- + +''' + - - - - - -- - - - - - - - - - - - - - - - - - - - - - - + Name - - CNN - Convolution Neural Network For Photo Recognizing + Goal - - Recognize Handing Writting Word Photo + Detail:Total 5 layers neural network + * Convolution layer + * Pooling layer + * Input layer layer of BP + * Hiden layer of BP + * Output layer of BP + Author: Stephen Lee + Program: PYTHON + Date: 2017.9.20 + - - - - - -- - - - - - - - - - - - - - - - - - - - - - - + ''' +import numpy as np +import matplotlib.pyplot as plt + + +class CNN(): + conv1 = [] + w_conv1 = [] + thre_conv1 = [] + step_conv1 = 0 + size_pooling1 = 0 + num_bp1 = 0 + num_bp2 = 0 + num_bp3 = 0 + thre_bp1 = [] + thre_bp2 = [] + wkj = np.mat([]) + vji = np.mat([]) + rate_weight = 0 + rate_thre = 0 + + + def __init__(self,conv1_get,size_p1,bp_num1,bp_num2,bp_num3,rate_w=0.2,rate_t=0.2): + ''' + :param conv1_get: [a,c,d],size, number, step of convolution kernel + :param size_p1: pooling size + :param bp_num1: units number of flatten layer + :param bp_num2: units number of hidden layer + :param bp_num3: units number of output layer + :param rate_w: rate of weight learning + :param rate_t: rate of threshold learning + ''' + self.num_bp1 = bp_num1 + self.num_bp2 = bp_num2 + self.num_bp3 = bp_num3 + self.conv1 = conv1_get[:2] + self.step_conv1 = conv1_get[2] + self.size_pooling1 = size_p1 + self.rate_weight = rate_w + self.rate_thre = rate_t + self.w_conv1 = [np.mat(-1*np.random.rand(self.conv1[0],self.conv1[0])+0.5) for i in range(self.conv1[1])] + self.wkj = np.mat(-1 * np.random.rand(self.num_bp3, self.num_bp2) + 0.5) + self.vji = np.mat(-1*np.random.rand(self.num_bp2, self.num_bp1)+0.5) + self.thre_conv1 = -2*np.random.rand(self.conv1[1])+1 + self.thre_bp2 = -2*np.random.rand(self.num_bp2)+1 + self.thre_bp3 = -2*np.random.rand(self.num_bp3)+1 + + + def save_model(self,save_path): + #将模型保存 + import pickle + model_dic = {'num_bp1':self.num_bp1, + 'num_bp2':self.num_bp2, + 'num_bp3':self.num_bp3, + 'conv1':self.conv1, + 'step_conv1':self.step_conv1, + 'size_pooling1':self.size_pooling1, + 'rate_weight':self.rate_weight, + 'rate_thre':self.rate_thre, + 'w_conv1':self.w_conv1, + 'wkj':self.wkj, + 'vji':self.vji, + 'thre_conv1':self.thre_conv1, + 'thre_bp2':self.thre_bp2, + 'thre_bp3':self.thre_bp3} + with open(save_path, 'wb') as f: + pickle.dump(model_dic, f) + + print('模型已经保存: %s'% save_path) + + + def paste_model(self,save_path): + #实例方法, + #虽然这么写一点也不简洁。。。。 + #卸载这个里面的话,只是用于修改已经存在的模型,要根据读取的数据返回实例的模型,再写一个吧 + import pickle + with open(save_path, 'rb') as f: + model_dic = pickle.load(f) + self.num_bp1 = model_dic.get('num_bp1') + self.num_bp2 = model_dic.get('num_bp2') + self.num_bp3 = model_dic.get('num_bp3') + self.conv1 = model_dic.get('conv1') + self.step_conv1 = model_dic.get('step_conv1') + self.size_pooling1 = model_dic.get('size_pooling1') + self.rate_weight = model_dic.get('rate_weight') + self.rate_thre = model_dic.get('rate_thre') + self.w_conv1 = model_dic.get('w_conv1') + self.wkj = model_dic.get('wkj') + self.vji = model_dic.get('vji') + self.thre_conv1 = model_dic.get('thre_conv1') + self.thre_bp2 = model_dic.get('thre_bp2') + self.thre_bp3 = model_dic.get('thre_bp3') + print('已经成功读取模型') + + @classmethod + def ReadModel(cls,model_path): + #类方法,读取保存的模型,返回一个实例。 + import pickle + with open(model_path, 'rb') as f: + model_dic = pickle.load(f) + + conv_get= model_dic.get('conv1') + conv_get.append(model_dic.get('step_conv1')) + size_p1 = model_dic.get('size_pooling1') + bp1 = model_dic.get('num_bp1') + bp2 = model_dic.get('num_bp2') + bp3 = model_dic.get('num_bp3') + r_w = model_dic.get('rate_weight') + r_t = model_dic.get('rate_thre') + #创建实例 + conv_ins = CNN(conv_get,size_p1,bp1,bp2,bp3,r_w,r_t) + #修改实例的参数 + conv_ins.w_conv1 = model_dic.get('w_conv1') + conv_ins.wkj = model_dic.get('wkj') + conv_ins.vji = model_dic.get('vji') + conv_ins.thre_conv1 = model_dic.get('thre_conv1') + conv_ins.thre_bp2 = model_dic.get('thre_bp2') + conv_ins.thre_bp3 = model_dic.get('thre_bp3') + return conv_ins + + + def sig(self,x): + return 1 / (1 + np.exp(-1*x)) + def do_round(self,x): + return round(x, 3) + #卷积 + def Convolute(self,data,convs,w_convs,thre_convs,conv_step): + size_conv = convs[0] + num_conv =convs[1] + size_data = np.shape(data)[0] + #得到原图像滑动的小图,data_focus + data_focus = [] + for i_focus in range(0, size_data - size_conv + 1, conv_step): + for j_focus in range(0, size_data - size_conv + 1, conv_step): + focus = data[i_focus:i_focus + size_conv, j_focus:j_focus + size_conv] + data_focus.append(focus) + #计算所有卷积核得到的特征图,每个特征图以矩阵形式,存储为一个列表data_featuremap + data_featuremap = [] + Size_FeatureMap = int((size_data - size_conv) / conv_step + 1) + for i_map in range(num_conv): + featuremap = [] + for i_focus in range(len(data_focus)): + net_focus = np.sum(np.multiply(data_focus[i_focus], w_convs[i_map])) - thre_convs[i_map] + featuremap.append(self.sig(net_focus)) + featuremap = np.asmatrix(featuremap).reshape(Size_FeatureMap, Size_FeatureMap) + data_featuremap.append(featuremap) + + #将data_focus中的focus展开为一维 + focus1_list = [] + for each_focus in data_focus: + focus1_list.extend(self.Expand_Mat(each_focus)) + focus_list = np.asarray(focus1_list) + return focus_list,data_featuremap + + # 池化 + def Pooling(self,featuremaps,size_pooling): + size_map = len(featuremaps[0]) + size_pooled = int(size_map/size_pooling) + featuremap_pooled = [] + for i_map in range(len(featuremaps)): + map = featuremaps[i_map] + map_pooled = [] + for i_focus in range(0,size_map,size_pooling): + for j_focus in range(0, size_map, size_pooling): + focus = map[i_focus:i_focus + size_pooling, j_focus:j_focus + size_pooling] + #平均池化 + map_pooled.append(np.average(focus)) + #最大池化 + #map_pooled.append(np.max(focus)) + map_pooled = np.asmatrix(map_pooled).reshape(size_pooled,size_pooled) + featuremap_pooled.append(map_pooled) + return featuremap_pooled + + def Expand(self,datas): + #将三元的数据展开为1为的list + data_expanded = [] + for i in range(len(datas)): + shapes = np.shape(datas[i]) + data_listed = datas[i].reshape(1,shapes[0]*shapes[1]) + data_listed = data_listed.getA().tolist()[0] + data_expanded.extend(data_listed) + #连接所有数据 + data_expanded = np.asarray(data_expanded) + return data_expanded + + def Expand_Mat(self,data_mat): + #用来展开矩阵为一维的list + data_mat = np.asarray(data_mat) + shapes = np.shape(data_mat) + data_expanded = data_mat.reshape(1,shapes[0]*shapes[1]) + return data_expanded + + def Getpd_From_Pool(self,out_map,pd_pool,num_map,size_map,size_pooling): + ''' + 误差反传,从pooled到前一个map, 例如将池化层6*6的误差矩阵扩大为12*12的误差矩阵 + pd_pool: 是采样层的误差,list形式。。。。要改要改 + out_map: 前面特征图的输出,数量*size*size的列表形式 + return: pd_all:前面层所有的特征图的pd, num*size_map*size_map的列表形式 + ''' + pd_all = [] + i_pool = 0 + for i_map in range(num_map): + pd_conv1 = np.ones((size_map, size_map)) + for i in range(0, size_map, size_pooling): + for j in range(0, size_map, size_pooling): + pd_conv1[i:i + size_pooling, j:j + size_pooling] = pd_pool[i_pool] + i_pool = i_pool + 1 + pd_conv2 = np.multiply(pd_conv1,np.multiply(out_map[i_map],(1-out_map[i_map]))) + pd_all.append(pd_conv2) + return pd_all + + def trian(self,patterns,datas_train, datas_teach, n_repeat, error_accuracy,draw_e = bool): + print('----------------------Start Training-------------------------') + print(' - - Shape: Train_Data ',np.shape(datas_train)) + print(' - - Shape: Teach_Data ',np.shape(datas_teach)) + rp = 0 + all_mse = [] + mse = 10000 + while rp < n_repeat and mse >= error_accuracy: + alle = 0 + print('-------------进行第%d次学习--------------'%rp) + for p in range(len(datas_train)): + #print('------------学习第%d个图像--------------'%p) + data_train = np.asmatrix(datas_train[p]) + data_teach = np.asarray(datas_teach[p]) + data_focus1,data_conved1 = self.Convolute(data_train,self.conv1,self.w_conv1, + self.thre_conv1,conv_step=self.step_conv1) + data_pooled1 = self.Pooling(data_conved1,self.size_pooling1) + shape_featuremap1 = np.shape(data_conved1) + ''' + print(' -----original shape ', np.shape(data_train)) + print(' ---- after convolution ',np.shape(data_conv1)) + print(' -----after pooling ',np.shape(data_pooled1)) + ''' + data_bp_input = self.Expand(data_pooled1) + # 计算第一层输入输出 + bp_out1 = data_bp_input + # 计算第二层输入输出 + bp_net_j = np.dot(bp_out1,self.vji.T) - self.thre_bp2 + bp_out2 = self.sig(bp_net_j) + # 计算第三层输入输出 + bp_net_k = np.dot(bp_out2 ,self.wkj.T) - self.thre_bp3 + bp_out3 = self.sig(bp_net_k) + + # 计算一般化误差 + pd_k_all = np.multiply((data_teach - bp_out3), np.multiply(bp_out3, (1 - bp_out3))) + pd_j_all = np.multiply(np.dot(pd_k_all,self.wkj), np.multiply(bp_out2, (1 - bp_out2))) + pd_i_all = np.dot(pd_j_all,self.vji) + + pd_conv1_pooled = pd_i_all / (self.size_pooling1*self.size_pooling1) + pd_conv1_pooled = pd_conv1_pooled.T.getA().tolist() + pd_conv1_all = self.Getpd_From_Pool(data_conved1,pd_conv1_pooled,shape_featuremap1[0], + shape_featuremap1[1],self.size_pooling1) + + #卷积层1的权重和阈值修正,每个卷积核的权重需要修正 12*12(map) 次 + #修正量为featuremap中点的偏导值 乘以 前一层图像focus, 整个权重模板一起更新 + for k_conv in range(self.conv1[1]): + pd_conv_list = self.Expand_Mat(pd_conv1_all[k_conv]) + delta_w = self.rate_weight * np.dot(pd_conv_list,data_focus1) + + self.w_conv1[k_conv] = self.w_conv1[k_conv] + delta_w.reshape((self.conv1[0],self.conv1[0])) + + self.thre_conv1[k_conv] = self.thre_conv1[k_conv] - np.sum(pd_conv1_all[k_conv]) * self.rate_thre + # 更新kj层的权重 + + self.wkj = self.wkj + pd_k_all.T * bp_out2 * self.rate_weight + # 更新ji层的权重 + self.vji = self.vji + pd_j_all.T * bp_out1 * self.rate_weight + # 更新阈值 + self.thre_bp3 = self.thre_bp3 - pd_k_all * self.rate_thre + self.thre_bp2 = self.thre_bp2 - pd_j_all * self.rate_thre + # 计算总误差 + errors = np.sum(abs((data_teach - bp_out3))) + alle = alle + errors + #print(' ----Teach ',data_teach) + #print(' ----BP_output ',bp_out3) + rp = rp + 1 + mse = alle/patterns + all_mse.append(mse) + def draw_error(): + yplot = [error_accuracy for i in range(int(n_repeat * 1.2))] + plt.plot(all_mse, '+-') + plt.plot(yplot, 'r--') + plt.xlabel('Learning Times') + plt.ylabel('All_mse') + plt.grid(True, alpha=0.5) + plt.show() + print('------------------Training Complished---------------------') + print(' - - Training epoch: ', rp, ' - - Mse: %.6f' % mse) + if draw_e: + draw_error() + return mse + + def produce(self,datas_test): + #对验证和测试数据集进行输出 + produce_out = [] + print('-------------------Start Testing-------------------------') + print(' - - Shape: Test_Data ',np.shape(datas_test)) + for p in range(len(datas_test)): + print('--------测试第%d个图像----------' % p) + data_test = np.asmatrix(datas_test[p]) + data_focus1, data_conved1 = self.Convolute(data_test, self.conv1, self.w_conv1, + self.thre_conv1, conv_step=self.step_conv1) + data_pooled1 = self.Pooling(data_conved1, self.size_pooling1) + data_bp_input = self.Expand(data_pooled1) + # 计算第一层输入输出 + bp_out1 = data_bp_input + # 计算第二层输入输出 + bp_net_j = bp_out1 * self.vji.T - self.thre_bp2 + bp_out2 = self.sig(bp_net_j) + # 计算第三层输入输出 + bp_net_k = bp_out2 * self.wkj.T - self.thre_bp3 + bp_out3 = self.sig(bp_net_k) + produce_out.extend(bp_out3.getA().tolist()) + res = [list(map(self.do_round,each)) for each in produce_out] + return np.asarray(res) + + def convolution(self,data): + #返回卷积和池化后的数据,用于查看图像 + data_test = np.asmatrix(data) + data_focus1, data_conved1 = self.Convolute(data_test, self.conv1, self.w_conv1, + self.thre_conv1, conv_step=self.step_conv1) + data_pooled1 = self.Pooling(data_conved1, self.size_pooling1) + + return data_conved1,data_pooled1 + + From 6e61ac19cd50288175b7b2c94d93133adc69492d Mon Sep 17 00:00:00 2001 From: Stephen Lee <245885195@qq.com> Date: Fri, 22 Sep 2017 14:56:20 +0800 Subject: [PATCH 02/29] commit convolution_neural_network.py --- Neural_Network/convolution_neural_network.py | 158 +++++++------------ 1 file changed, 60 insertions(+), 98 deletions(-) diff --git a/Neural_Network/convolution_neural_network.py b/Neural_Network/convolution_neural_network.py index 539c315a0..d8ab0d2e5 100644 --- a/Neural_Network/convolution_neural_network.py +++ b/Neural_Network/convolution_neural_network.py @@ -11,30 +11,15 @@ * Hiden layer of BP * Output layer of BP Author: Stephen Lee - Program: PYTHON + Github: 245885195@qq.com Date: 2017.9.20 - - - - - -- - - - - - - - - - - - - - - - - - - - - - - ''' + import numpy as np import matplotlib.pyplot as plt - class CNN(): - conv1 = [] - w_conv1 = [] - thre_conv1 = [] - step_conv1 = 0 - size_pooling1 = 0 - num_bp1 = 0 - num_bp2 = 0 - num_bp3 = 0 - thre_bp1 = [] - thre_bp2 = [] - wkj = np.mat([]) - vji = np.mat([]) - rate_weight = 0 - rate_thre = 0 - def __init__(self,conv1_get,size_p1,bp_num1,bp_num2,bp_num3,rate_w=0.2,rate_t=0.2): ''' @@ -63,7 +48,7 @@ class CNN(): def save_model(self,save_path): - #将模型保存 + #save model dict with pickle import pickle model_dic = {'num_bp1':self.num_bp1, 'num_bp2':self.num_bp2, @@ -82,35 +67,11 @@ class CNN(): with open(save_path, 'wb') as f: pickle.dump(model_dic, f) - print('模型已经保存: %s'% save_path) - - - def paste_model(self,save_path): - #实例方法, - #虽然这么写一点也不简洁。。。。 - #卸载这个里面的话,只是用于修改已经存在的模型,要根据读取的数据返回实例的模型,再写一个吧 - import pickle - with open(save_path, 'rb') as f: - model_dic = pickle.load(f) - self.num_bp1 = model_dic.get('num_bp1') - self.num_bp2 = model_dic.get('num_bp2') - self.num_bp3 = model_dic.get('num_bp3') - self.conv1 = model_dic.get('conv1') - self.step_conv1 = model_dic.get('step_conv1') - self.size_pooling1 = model_dic.get('size_pooling1') - self.rate_weight = model_dic.get('rate_weight') - self.rate_thre = model_dic.get('rate_thre') - self.w_conv1 = model_dic.get('w_conv1') - self.wkj = model_dic.get('wkj') - self.vji = model_dic.get('vji') - self.thre_conv1 = model_dic.get('thre_conv1') - self.thre_bp2 = model_dic.get('thre_bp2') - self.thre_bp3 = model_dic.get('thre_bp3') - print('已经成功读取模型') + print('Model saved: %s'% save_path) @classmethod def ReadModel(cls,model_path): - #类方法,读取保存的模型,返回一个实例。 + #read saved model import pickle with open(model_path, 'rb') as f: model_dic = pickle.load(f) @@ -123,9 +84,9 @@ class CNN(): bp3 = model_dic.get('num_bp3') r_w = model_dic.get('rate_weight') r_t = model_dic.get('rate_thre') - #创建实例 + #create model instance conv_ins = CNN(conv_get,size_p1,bp1,bp2,bp3,r_w,r_t) - #修改实例的参数 + #modify model parameter conv_ins.w_conv1 = model_dic.get('w_conv1') conv_ins.wkj = model_dic.get('wkj') conv_ins.vji = model_dic.get('vji') @@ -137,20 +98,22 @@ class CNN(): def sig(self,x): return 1 / (1 + np.exp(-1*x)) + def do_round(self,x): return round(x, 3) - #卷积 - def Convolute(self,data,convs,w_convs,thre_convs,conv_step): + + def convolute(self,data,convs,w_convs,thre_convs,conv_step): + #convolution process size_conv = convs[0] num_conv =convs[1] size_data = np.shape(data)[0] - #得到原图像滑动的小图,data_focus + #get the data slice of original image data, data_focus data_focus = [] for i_focus in range(0, size_data - size_conv + 1, conv_step): for j_focus in range(0, size_data - size_conv + 1, conv_step): focus = data[i_focus:i_focus + size_conv, j_focus:j_focus + size_conv] data_focus.append(focus) - #计算所有卷积核得到的特征图,每个特征图以矩阵形式,存储为一个列表data_featuremap + #caculate the feature map of every single kernel, and saved as list of matrix data_featuremap = [] Size_FeatureMap = int((size_data - size_conv) / conv_step + 1) for i_map in range(num_conv): @@ -161,15 +124,15 @@ class CNN(): featuremap = np.asmatrix(featuremap).reshape(Size_FeatureMap, Size_FeatureMap) data_featuremap.append(featuremap) - #将data_focus中的focus展开为一维 + #expanding the data slice to One dimenssion focus1_list = [] for each_focus in data_focus: focus1_list.extend(self.Expand_Mat(each_focus)) focus_list = np.asarray(focus1_list) return focus_list,data_featuremap - # 池化 - def Pooling(self,featuremaps,size_pooling): + def pooling(self,featuremaps,size_pooling,type='average_pool'): + #pooling process size_map = len(featuremaps[0]) size_pooled = int(size_map/size_pooling) featuremap_pooled = [] @@ -179,39 +142,40 @@ class CNN(): for i_focus in range(0,size_map,size_pooling): for j_focus in range(0, size_map, size_pooling): focus = map[i_focus:i_focus + size_pooling, j_focus:j_focus + size_pooling] - #平均池化 - map_pooled.append(np.average(focus)) - #最大池化 - #map_pooled.append(np.max(focus)) + if type == 'average_pool': + #average pooling + map_pooled.append(np.average(focus)) + elif type == 'max_pooling': + #max pooling + map_pooled.append(np.max(focus)) map_pooled = np.asmatrix(map_pooled).reshape(size_pooled,size_pooled) featuremap_pooled.append(map_pooled) return featuremap_pooled - def Expand(self,datas): - #将三元的数据展开为1为的list + def _expand(self,datas): + #expanding three dimension data to one dimension list data_expanded = [] for i in range(len(datas)): shapes = np.shape(datas[i]) data_listed = datas[i].reshape(1,shapes[0]*shapes[1]) data_listed = data_listed.getA().tolist()[0] data_expanded.extend(data_listed) - #连接所有数据 data_expanded = np.asarray(data_expanded) return data_expanded - def Expand_Mat(self,data_mat): - #用来展开矩阵为一维的list + def _expand_mat(self,data_mat): + #expanding matrix to one dimension list data_mat = np.asarray(data_mat) shapes = np.shape(data_mat) data_expanded = data_mat.reshape(1,shapes[0]*shapes[1]) return data_expanded - def Getpd_From_Pool(self,out_map,pd_pool,num_map,size_map,size_pooling): + def _calculate_gradient_from_pool(self,out_map,pd_pool,num_map,size_map,size_pooling): ''' - 误差反传,从pooled到前一个map, 例如将池化层6*6的误差矩阵扩大为12*12的误差矩阵 - pd_pool: 是采样层的误差,list形式。。。。要改要改 - out_map: 前面特征图的输出,数量*size*size的列表形式 - return: pd_all:前面层所有的特征图的pd, num*size_map*size_map的列表形式 + calcluate the gradient from the data slice of pool layer + pd_pool: list of matrix + out_map: the shape of data slice(size_map*size_map) + return: pd_all: list of matrix, [num, size_map, size_map] ''' pd_all = [] i_pool = 0 @@ -226,6 +190,7 @@ class CNN(): return pd_all def trian(self,patterns,datas_train, datas_teach, n_repeat, error_accuracy,draw_e = bool): + #model traning print('----------------------Start Training-------------------------') print(' - - Shape: Train_Data ',np.shape(datas_train)) print(' - - Shape: Teach_Data ',np.shape(datas_teach)) @@ -234,58 +199,53 @@ class CNN(): mse = 10000 while rp < n_repeat and mse >= error_accuracy: alle = 0 - print('-------------进行第%d次学习--------------'%rp) + print('-------------Learning Time %d--------------'%rp) for p in range(len(datas_train)): - #print('------------学习第%d个图像--------------'%p) + #print('------------Learning Image: %d--------------'%p) data_train = np.asmatrix(datas_train[p]) data_teach = np.asarray(datas_teach[p]) - data_focus1,data_conved1 = self.Convolute(data_train,self.conv1,self.w_conv1, + data_focus1,data_conved1 = self.convolute(data_train,self.conv1,self.w_conv1, self.thre_conv1,conv_step=self.step_conv1) - data_pooled1 = self.Pooling(data_conved1,self.size_pooling1) + data_pooled1 = self.pooling(data_conved1,self.size_pooling1) shape_featuremap1 = np.shape(data_conved1) ''' print(' -----original shape ', np.shape(data_train)) print(' ---- after convolution ',np.shape(data_conv1)) print(' -----after pooling ',np.shape(data_pooled1)) ''' - data_bp_input = self.Expand(data_pooled1) - # 计算第一层输入输出 + data_bp_input = self._expand(data_pooled1) bp_out1 = data_bp_input - # 计算第二层输入输出 + bp_net_j = np.dot(bp_out1,self.vji.T) - self.thre_bp2 bp_out2 = self.sig(bp_net_j) - # 计算第三层输入输出 bp_net_k = np.dot(bp_out2 ,self.wkj.T) - self.thre_bp3 bp_out3 = self.sig(bp_net_k) - # 计算一般化误差 + #--------------Model Leaning ------------------------ + # calcluate error and gradient--------------- pd_k_all = np.multiply((data_teach - bp_out3), np.multiply(bp_out3, (1 - bp_out3))) pd_j_all = np.multiply(np.dot(pd_k_all,self.wkj), np.multiply(bp_out2, (1 - bp_out2))) pd_i_all = np.dot(pd_j_all,self.vji) pd_conv1_pooled = pd_i_all / (self.size_pooling1*self.size_pooling1) pd_conv1_pooled = pd_conv1_pooled.T.getA().tolist() - pd_conv1_all = self.Getpd_From_Pool(data_conved1,pd_conv1_pooled,shape_featuremap1[0], + pd_conv1_all = self._calculate_gradient_from_pool(data_conved1,pd_conv1_pooled,shape_featuremap1[0], shape_featuremap1[1],self.size_pooling1) - - #卷积层1的权重和阈值修正,每个卷积核的权重需要修正 12*12(map) 次 - #修正量为featuremap中点的偏导值 乘以 前一层图像focus, 整个权重模板一起更新 + #weight and threshold learning process--------- + #convolution layer for k_conv in range(self.conv1[1]): - pd_conv_list = self.Expand_Mat(pd_conv1_all[k_conv]) + pd_conv_list = self._expand_mat(pd_conv1_all[k_conv]) delta_w = self.rate_weight * np.dot(pd_conv_list,data_focus1) self.w_conv1[k_conv] = self.w_conv1[k_conv] + delta_w.reshape((self.conv1[0],self.conv1[0])) self.thre_conv1[k_conv] = self.thre_conv1[k_conv] - np.sum(pd_conv1_all[k_conv]) * self.rate_thre - # 更新kj层的权重 - + #all connected layer self.wkj = self.wkj + pd_k_all.T * bp_out2 * self.rate_weight - # 更新ji层的权重 self.vji = self.vji + pd_j_all.T * bp_out1 * self.rate_weight - # 更新阈值 self.thre_bp3 = self.thre_bp3 - pd_k_all * self.rate_thre self.thre_bp2 = self.thre_bp2 - pd_j_all * self.rate_thre - # 计算总误差 + # calculate the sum error of all single image errors = np.sum(abs((data_teach - bp_out3))) alle = alle + errors #print(' ----Teach ',data_teach) @@ -307,24 +267,21 @@ class CNN(): draw_error() return mse - def produce(self,datas_test): - #对验证和测试数据集进行输出 + def predict(self,datas_test): + #model predict produce_out = [] print('-------------------Start Testing-------------------------') print(' - - Shape: Test_Data ',np.shape(datas_test)) for p in range(len(datas_test)): - print('--------测试第%d个图像----------' % p) data_test = np.asmatrix(datas_test[p]) - data_focus1, data_conved1 = self.Convolute(data_test, self.conv1, self.w_conv1, + data_focus1, data_conved1 = self.convolute(data_test, self.conv1, self.w_conv1, self.thre_conv1, conv_step=self.step_conv1) - data_pooled1 = self.Pooling(data_conved1, self.size_pooling1) - data_bp_input = self.Expand(data_pooled1) - # 计算第一层输入输出 + data_pooled1 = self.pooling(data_conved1, self.size_pooling1) + data_bp_input = self._expand(data_pooled1) + bp_out1 = data_bp_input - # 计算第二层输入输出 bp_net_j = bp_out1 * self.vji.T - self.thre_bp2 bp_out2 = self.sig(bp_net_j) - # 计算第三层输入输出 bp_net_k = bp_out2 * self.wkj.T - self.thre_bp3 bp_out3 = self.sig(bp_net_k) produce_out.extend(bp_out3.getA().tolist()) @@ -332,12 +289,17 @@ class CNN(): return np.asarray(res) def convolution(self,data): - #返回卷积和池化后的数据,用于查看图像 + #return the data of image after convoluting process so we can check it out data_test = np.asmatrix(data) - data_focus1, data_conved1 = self.Convolute(data_test, self.conv1, self.w_conv1, + data_focus1, data_conved1 = self.convolute(data_test, self.conv1, self.w_conv1, self.thre_conv1, conv_step=self.step_conv1) - data_pooled1 = self.Pooling(data_conved1, self.size_pooling1) + data_pooled1 = self.pooling(data_conved1, self.size_pooling1) return data_conved1,data_pooled1 +if __name__ == '__main__': + pass + ''' + I will put the example on other file + ''' \ No newline at end of file From 1958cf25c5e636e695a7cbed529a013f3a4704cd Mon Sep 17 00:00:00 2001 From: theycallmemac Date: Thu, 28 Sep 2017 20:54:15 +0100 Subject: [PATCH 03/29] added timsort.py --- sorts/timsort.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 sorts/timsort.py diff --git a/sorts/timsort.py b/sorts/timsort.py new file mode 100644 index 000000000..04360e256 --- /dev/null +++ b/sorts/timsort.py @@ -0,0 +1,68 @@ +def binary_search(the_array, item, start, end): + if start == end: + if the_array[start] > item: + return start + else: + return start + 1 + if start > end: + return start + + mid = (start + end)/ 2 + if the_array[mid] < item: + return binary_search(the_array, item, mid + 1, end) + elif the_array[mid] > item: + return binary_search(the_array, item, start, mid - 1) + else: + return mid + + +""" +Insertion sort that the heap sort uses if the array size is small or if +the size of the "run" is small +""" +def insertion_sort(the_array): + l = len(the_array) + for index in range(1, l): + value = the_array[index] + pos = binary_search(the_array, value, 0, index - 1) + the_array = the_array[:pos] + [value] + the_array[pos:index] + the_array[index+1:] + return the_array + +def merge(left, right): + """Takes two sorted lists and returns a single sorted list by comparing the + elements one at a time. + [1, 2, 3, 4, 5, 6] + """ + if not left: + return right + if not right: + return left + if left[0] < right[0]: + return [left[0]] + merge(left[1:], right) + return [right[0]] + merge(left, right[1:]) + + +def timsort(the_array): + runs, sorted_runs = [], [] + l = len(the_array) + new_run = [the_array[0]] + for i in range(1, l): + if i == l-1: + new_run.append(the_array[i]) + runs.append(new_run) + break + if the_array[i] < the_array[i-1]: + if not new_run: + runs.append([the_array[i-1]]) + new_run.append(the_array[i]) + else: + runs.append(new_run) + new_run = [] + else: + new_run.append(the_array[i]) + for each in runs: + sorted_runs.append(insertion_sort(each)) + sorted_array = [] + for run in sorted_runs: + sorted_array = merge(sorted_array, run) +print(sorted_array) From edcf6d54b6304d3e3bead3b1d2d7d14d04b70aab Mon Sep 17 00:00:00 2001 From: KuLi Date: Fri, 29 Sep 2017 23:47:24 +0200 Subject: [PATCH 04/29] #130 fixed radix sort for python 3 --- sorts/radix_sort.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sorts/radix_sort.py b/sorts/radix_sort.py index 82f8a38b4..f19bc10e8 100644 --- a/sorts/radix_sort.py +++ b/sorts/radix_sort.py @@ -2,19 +2,19 @@ def radixsort(lst): RADIX = 10 maxLength = False tmp , placement = -1, 1 - + while not maxLength: maxLength = True # declare and initialize buckets buckets = [list() for _ in range( RADIX )] - + # split lst between lists for i in lst: - tmp = i / placement + tmp = i // placement buckets[tmp % RADIX].append( i ) if maxLength and tmp > 0: maxLength = False - + # empty lists into lst array a = 0 for b in range( RADIX ): @@ -22,6 +22,6 @@ def radixsort(lst): for i in buck: lst[a] = i a += 1 - + # move to next placement *= RADIX From 4d4b0ff31a88d13e42021687b8a0cd3e5db09d78 Mon Sep 17 00:00:00 2001 From: malikshubham827 Date: Sun, 1 Oct 2017 00:06:03 +0530 Subject: [PATCH 05/29] Added Dijkstra Algorithm --- data_structures/Graph/dijkstra_algorithm.py | 211 ++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 data_structures/Graph/dijkstra_algorithm.py diff --git a/data_structures/Graph/dijkstra_algorithm.py b/data_structures/Graph/dijkstra_algorithm.py new file mode 100644 index 000000000..c43ff37f5 --- /dev/null +++ b/data_structures/Graph/dijkstra_algorithm.py @@ -0,0 +1,211 @@ +# Title: Dijkstra's Algorithm for finding single source shortest path from scratch +# Author: Shubham Malik +# References: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + +import math +import sys +# For storing the vertex set to retreive node with the lowest distance + + +class PriorityQueue: + # Based on Min Heap + def __init__(self): + self.cur_size = 0 + self.array = [] + self.pos = {} # To store the pos of node in array + + def isEmpty(self): + return self.cur_size == 0 + + def min_heapify(self, idx): + lc = self.left(idx) + rc = self.right(idx) + if lc < self.cur_size and self.array(lc)[0] < self.array(idx)[0]: + smallest = lc + else: + smallest = idx + if rc < self.cur_size and self.array(rc)[0] < self.array(smallest)[0]: + smallest = rc + if smallest != idx: + self.swap(idx, smallest) + self.min_heapify(smallest) + + def insert(self, tup): + # Inserts a node into the Priority Queue + self.pos[tup[1]] = self.cur_size + self.cur_size += 1 + self.array.append((sys.maxsize, tup[1])) + self.decrease_key((sys.maxsize, tup[1]), tup[0]) + + def extract_min(self): + # Removes and returns the min element at top of priority queue + min_node = self.array[0][1] + self.array[0] = self.array[self.cur_size - 1] + self.cur_size -= 1 + self.min_heapify(1) + del self.pos[min_node] + return min_node + + def left(self, i): + # returns the index of left child + return 2 * i + 1 + + def right(self, i): + # returns the index of right child + return 2 * i + 2 + + def par(self, i): + # returns the index of parent + return math.floor(i / 2) + + def swap(self, i, j): + # swaps array elements at indices i and j + # update the pos{} + self.pos[self.array[i][1]] = j + self.pos[self.array[j][1]] = i + temp = self.array[i] + self.array[i] = self.array[j] + self.array[j] = temp + + def decrease_key(self, tup, new_d): + idx = self.pos[tup[1]] + # assuming the new_d is atmost old_d + self.array[idx] = (new_d, tup[1]) + while idx > 0 and self.array[self.par(idx)][0] > self.array[idx][0]: + self.swap(idx, self.par(idx)) + idx = self.par(idx) + + +class Graph: + def __init__(self, num): + self.adjList = {} # To store graph: u -> (v,w) + self.num_nodes = num # Number of nodes in graph + # To store the distance from source vertex + self.dist = [0] * self.num_nodes + self.par = [-1] * self.num_nodes # To store the path + + def add_edge(self, u, v, w): + # Edge going from node u to v and v to u with weight w + # u (w)-> v, v (w) -> u + # Check if u already in graph + if u in self.adjList.keys(): + self.adjList[u].append((v, w)) + else: + self.adjList[u] = [(v, w)] + + # Assuming undirected graph + if v in self.adjList.keys(): + self.adjList[v].append((u, w)) + else: + self.adjList[v] = [(u, w)] + + def show_graph(self): + # u -> v(w) + for u in self.adjList: + print(u, '->', ' -> '.join(str("{}({})".format(v, w)) + for v, w in self.adjList[u])) + + def dijkstra(self, src): + # Flush old junk values in par[] + self.par = [-1] * self.num_nodes + # src is the source node + self.dist[src] = 0 + Q = PriorityQueue() + Q.insert((0, src)) # (dist from src, node) + for u in self.adjList.keys(): + if u != src: + self.dist[u] = sys.maxsize # Infinity + self.par[u] = -1 + + while not Q.isEmpty(): + u = Q.extract_min() # Returns node with the min dist from source + # Update the distance of all the neighbours of u and + # if their prev dist was INFINITY then push them in Q + for v, w in self.adjList[u]: + new_dist = self.dist[u] + w + if self.dist[v] > new_dist: + if self.dist[v] == sys.maxsize: + Q.insert((new_dist, v)) + else: + Q.decrease_key((self.dist[v], v), new_dist) + self.dist[v] = new_dist + self.par[v] = u + + # Show the shortest distances from src + self.show_distances(src) + + def show_distances(self, src): + print("Distance from node: {}".format(src)) + for u in range(self.num_nodes): + print('Node {} has distance: {}'.format(u, self.dist[u])) + + def show_path(self, src, dest): + # To show the shortest path from src to dest + # WARNING: Use it *after* calling dijkstra + path = [] + cost = 0 + temp = dest + # Backtracking from dest to src + while self.par[temp] != -1: + path.append(temp) + if temp != src: + for v, w in self.adjList[temp]: + if v == self.par[temp]: + cost += w + break + temp = self.par[temp] + path.append(src) + path.reverse() + + print('----Path to reach {} from {}----'.format(dest, src)) + for u in path: + print('{}'.format(u), end=' ') + if u != dest: + print('-> ', end='') + + print('\nTotal cost of path: ', cost) + + +if __name__ == '__main__': + graph = Graph(9) + graph.add_edge(0, 1, 4) + graph.add_edge(0, 7, 8) + graph.add_edge(1, 2, 8) + graph.add_edge(1, 7, 11) + graph.add_edge(2, 3, 7) + graph.add_edge(2, 8, 2) + graph.add_edge(2, 5, 4) + graph.add_edge(3, 4, 9) + graph.add_edge(3, 5, 14) + graph.add_edge(4, 5, 10) + graph.add_edge(5, 6, 2) + graph.add_edge(6, 7, 1) + graph.add_edge(6, 8, 6) + graph.add_edge(7, 8, 7) + graph.show_graph() + graph.dijkstra(0) + graph.show_path(0, 4) + +# OUTPUT +# 0 -> 1(4) -> 7(8) +# 1 -> 0(4) -> 2(8) -> 7(11) +# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7) +# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4) +# 3 -> 2(7) -> 4(9) -> 5(14) +# 8 -> 2(2) -> 6(6) -> 7(7) +# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2) +# 4 -> 3(9) -> 5(10) +# 6 -> 5(2) -> 7(1) -> 8(6) +# Distance from node: 0 +# Node 0 has distance: 0 +# Node 1 has distance: 4 +# Node 2 has distance: 12 +# Node 3 has distance: 19 +# Node 4 has distance: 21 +# Node 5 has distance: 11 +# Node 6 has distance: 9 +# Node 7 has distance: 8 +# Node 8 has distance: 14 +# ----Path to reach 4 from 0---- +# 0 -> 7 -> 6 -> 5 -> 4 +# Total cost of path: 21 From 2480eacdcc5927933b9f2d6de8a9f93ecaa6687b Mon Sep 17 00:00:00 2001 From: Juan Antonio Date: Sun, 1 Oct 2017 14:50:45 +0200 Subject: [PATCH 06/29] Adding Euclidean GCD algorithm --- other/euclidean_gcd.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 other/euclidean_gcd.py diff --git a/other/euclidean_gcd.py b/other/euclidean_gcd.py new file mode 100644 index 000000000..13378379f --- /dev/null +++ b/other/euclidean_gcd.py @@ -0,0 +1,18 @@ +# https://en.wikipedia.org/wiki/Euclidean_algorithm + +def euclidean_gcd(a, b): + while b: + t = b + b = a % b + a = t + return a + +def main(): + print("GCD(3, 5) = " + str(euclidean_gcd(3, 5))) + print("GCD(5, 3) = " + str(euclidean_gcd(5, 3))) + print("GCD(1, 3) = " + str(euclidean_gcd(1, 3))) + print("GCD(3, 6) = " + str(euclidean_gcd(3, 6))) + print("GCD(6, 3) = " + str(euclidean_gcd(6, 3))) + +if __name__ == '__main__': + main() From a97ab2f4e433e41a38fd28307a02f412c4fb3a01 Mon Sep 17 00:00:00 2001 From: James Mc Dermott Date: Sun, 1 Oct 2017 22:13:54 +0100 Subject: [PATCH 07/29] Update timsort.py --- sorts/timsort.py | 85 ++++++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/sorts/timsort.py b/sorts/timsort.py index 04360e256..8c75b5191 100644 --- a/sorts/timsort.py +++ b/sorts/timsort.py @@ -1,68 +1,81 @@ -def binary_search(the_array, item, start, end): +def binary_search(lst, item, start, end): if start == end: - if the_array[start] > item: + if lst[start] > item: return start else: return start + 1 if start > end: return start - mid = (start + end)/ 2 - if the_array[mid] < item: - return binary_search(the_array, item, mid + 1, end) - elif the_array[mid] > item: - return binary_search(the_array, item, start, mid - 1) + mid = (start + end) // 2 + if lst[mid] < item: + return binary_search(lst, item, mid + 1, end) + elif lst[mid] > item: + return binary_search(lst, item, start, mid - 1) else: return mid -""" -Insertion sort that the heap sort uses if the array size is small or if -the size of the "run" is small -""" -def insertion_sort(the_array): - l = len(the_array) - for index in range(1, l): - value = the_array[index] - pos = binary_search(the_array, value, 0, index - 1) - the_array = the_array[:pos] + [value] + the_array[pos:index] + the_array[index+1:] - return the_array +def insertion_sort(lst): + length = len(lst) + + for index in range(1, length): + value = lst[index] + pos = binary_search(lst, value, 0, index - 1) + lst = lst[:pos] + [value] + lst[pos:index] + lst[index+1:] + + return lst + def merge(left, right): - """Takes two sorted lists and returns a single sorted list by comparing the - elements one at a time. - [1, 2, 3, 4, 5, 6] - """ if not left: return right + if not right: return left + if left[0] < right[0]: return [left[0]] + merge(left[1:], right) + return [right[0]] + merge(left, right[1:]) -def timsort(the_array): +def timsort(lst): runs, sorted_runs = [], [] - l = len(the_array) - new_run = [the_array[0]] - for i in range(1, l): - if i == l-1: - new_run.append(the_array[i]) + length = len(lst) + new_run = [lst[0]] + sorted_array = [] + + for i in range(1, length): + if i == length - 1: + new_run.append(lst[i]) runs.append(new_run) break - if the_array[i] < the_array[i-1]: + + if lst[i] < lst[i - 1]: if not new_run: - runs.append([the_array[i-1]]) - new_run.append(the_array[i]) + runs.append([lst[i - 1]]) + new_run.append(lst[i]) else: runs.append(new_run) new_run = [] else: - new_run.append(the_array[i]) - for each in runs: - sorted_runs.append(insertion_sort(each)) - sorted_array = [] + new_run.append(lst[i]) + + for run in runs: + sorted_runs.append(insertion_sort(run)) + for run in sorted_runs: sorted_array = merge(sorted_array, run) -print(sorted_array) + + return sorted_array + + +def main(): + + lst = [5,9,10,3,-4,5,178,92,46,-18,0,7] + sorted_lst = timsort(lst) + print(sorted_lst) + +if __name__ == '__main__': + main() From 9ba6426aad2fee8b4676da0e04079194d197485c Mon Sep 17 00:00:00 2001 From: rudrasohan Date: Tue, 3 Oct 2017 20:29:29 +0530 Subject: [PATCH 08/29] Added A* Algorithm --- Graphs/A*.py | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Graphs/A*.py diff --git a/Graphs/A*.py b/Graphs/A*.py new file mode 100644 index 000000000..21f346225 --- /dev/null +++ b/Graphs/A*.py @@ -0,0 +1,101 @@ + +grid = [[0, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0],#0 are free path whereas 1's are obstacles + [0, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 1, 0], + [0, 0, 0, 0, 1, 0]] + +''' +heuristic = [[9, 8, 7, 6, 5, 4], + [8, 7, 6, 5, 4, 3], + [7, 6, 5, 4, 3, 2], + [6, 5, 4, 3, 2, 1], + [5, 4, 3, 2, 1, 0]]''' + +init = [0, 0] +goal = [len(grid)-1, len(grid[0])-1] +cost = 1 + +#the cost map which pushes the path closer to the goal +heuristic = [[0 for row in range(len(grid[0]))] for col in range(len(grid))] +for i in range(len(grid)): + for j in range(len(grid[0])): + heuristic[i][j] = abs(i - goal[0]) + abs(j - goal[1]) + if grid[i][j] == 1: + heuristic[i][j] = 99 #added extra penalty in the heuristic map + + +#the actions we can take +delta = [[-1, 0 ], # go up + [ 0, -1], # go left + [ 1, 0 ], # go down + [ 0, 1 ]] # go right + + +#function to search the path +def search(grid,init,goal,cost,heuristic): + + closed = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]# the referrence grid + closed[init[0]][init[1]] = 1 + action = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]#the action grid + + x = init[0] + y = init[1] + g = 0 + f = g + heuristic[init[0]][init[0]] + cell = [[f, g, x, y]] + + found = False # flag that is set when search is complete + resign = False # flag set if we can't find expand + + while not found and not resign: + if len(cell) == 0: + resign = True + return "FAIL" + else: + cell.sort()#to choose the least costliest action so as to move closer to the goal + cell.reverse() + next = cell.pop() + x = next[2] + y = next[3] + g = next[1] + f = next[0] + + + if x == goal[0] and y == goal[1]: + found = True + else: + for i in range(len(delta)):#to try out different valid actions + x2 = x + delta[i][0] + y2 = y + delta[i][1] + if x2 >= 0 and x2 < len(grid) and y2 >=0 and y2 < len(grid[0]): + if closed[x2][y2] == 0 and grid[x2][y2] == 0: + g2 = g + cost + f2 = g2 + heuristic[x2][y2] + cell.append([f2, g2, x2, y2]) + closed[x2][y2] = 1 + action[x2][y2] = i + invpath = [] + x = goal[0] + y = goal[1] + invpath.append([x, y])#we get the reverse path from here + while x != init[0] or y != init[1]: + x2 = x - delta[action[x][y]][0] + y2 = y - delta[action[x][y]][1] + x = x2 + y = y2 + invpath.append([x, y]) + + path = [] + for i in range(len(invpath)): + path.append(invpath[len(invpath) - 1 - i]) + print "ACTION MAP" + for i in range(len(action)): + print action[i] + + return path + +a = search(grid,init,goal,cost,heuristic) +for i in range(len(a)): + print a[i] + From 271cc48a2bf7057c1aaf24b792691e2d9e4a881e Mon Sep 17 00:00:00 2001 From: Sohan Rudra Date: Tue, 3 Oct 2017 21:10:34 +0530 Subject: [PATCH 09/29] Update A*.py --- Graphs/A*.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graphs/A*.py b/Graphs/A*.py index 21f346225..2ca9476e5 100644 --- a/Graphs/A*.py +++ b/Graphs/A*.py @@ -13,7 +13,7 @@ heuristic = [[9, 8, 7, 6, 5, 4], [5, 4, 3, 2, 1, 0]]''' init = [0, 0] -goal = [len(grid)-1, len(grid[0])-1] +goal = [len(grid)-1, len(grid[0])-1] #all coordinates are given in format [y,x] cost = 1 #the cost map which pushes the path closer to the goal From 2a916b010b9ccb2aee2d8f6a7cfffd45b6a3cbc9 Mon Sep 17 00:00:00 2001 From: b1o0d4x3 Date: Fri, 6 Oct 2017 15:24:56 +0530 Subject: [PATCH 10/29] Delete P01_BreadthFirstSearch.py --- .../Graph/P01_BreadthFirstSearch.py | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 data_structures/Graph/P01_BreadthFirstSearch.py diff --git a/data_structures/Graph/P01_BreadthFirstSearch.py b/data_structures/Graph/P01_BreadthFirstSearch.py deleted file mode 100644 index 16b1b2007..000000000 --- a/data_structures/Graph/P01_BreadthFirstSearch.py +++ /dev/null @@ -1,61 +0,0 @@ -# Author: OMKAR PATHAK - -class Graph(): - def __init__(self): - self.vertex = {} - - # for printing the Graph vertexes - def printGraph(self): - for i in self.vertex.keys(): - print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) - - # for adding the edge beween two vertexes - def addEdge(self, fromVertex, toVertex): - # check if vertex is already present, - if fromVertex in self.vertex.keys(): - self.vertex[fromVertex].append(toVertex) - else: - # else make a new vertex - self.vertex[fromVertex] = [toVertex] - - def BFS(self, startVertex): - # Take a list for stoting already visited vertexes - visited = [False] * len(self.vertex) - - # create a list to store all the vertexes for BFS - queue = [] - - # mark the source node as visited and enqueue it - visited[startVertex] = True - queue.append(startVertex) - - while queue: - startVertex = queue.pop(0) - print(startVertex, end = ' ') - - # mark all adjacent nodes as visited and print them - for i in self.vertex[startVertex]: - if visited[i] == False: - queue.append(i) - visited[i] = True - -if __name__ == '__main__': - g = Graph() - g.addEdge(0, 1) - g.addEdge(0, 2) - g.addEdge(1, 2) - g.addEdge(2, 0) - g.addEdge(2, 3) - g.addEdge(3, 3) - - g.printGraph() - print('BFS:') - g.BFS(2) - - # OUTPUT: - # 0  ->  1 -> 2 - # 1  ->  2 - # 2  ->  0 -> 3 - # 3  ->  3 - # BFS: - # 2 0 3 1 From d33044eb058b0fd5e04aef5620996cbe110589bf Mon Sep 17 00:00:00 2001 From: b1o0d4x3 Date: Fri, 6 Oct 2017 15:25:25 +0530 Subject: [PATCH 11/29] Delete P02_DepthFirstSearch.py --- data_structures/Graph/P02_DepthFirstSearch.py | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 data_structures/Graph/P02_DepthFirstSearch.py diff --git a/data_structures/Graph/P02_DepthFirstSearch.py b/data_structures/Graph/P02_DepthFirstSearch.py deleted file mode 100644 index 94ef3cb86..000000000 --- a/data_structures/Graph/P02_DepthFirstSearch.py +++ /dev/null @@ -1,61 +0,0 @@ -# Author: OMKAR PATHAK - -class Graph(): - def __init__(self): - self.vertex = {} - - # for printing the Graph vertexes - def printGraph(self): - print(self.vertex) - for i in self.vertex.keys(): - print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) - - # for adding the edge beween two vertexes - def addEdge(self, fromVertex, toVertex): - # check if vertex is already present, - if fromVertex in self.vertex.keys(): - self.vertex[fromVertex].append(toVertex) - else: - # else make a new vertex - self.vertex[fromVertex] = [toVertex] - - def DFS(self): - # visited array for storing already visited nodes - visited = [False] * len(self.vertex) - - # call the recursive helper function - for i in range(len(self.vertex)): - if visited[i] == False: - self.DFSRec(i, visited) - - def DFSRec(self, startVertex, visited): - # mark start vertex as visited - visited[startVertex] = True - - print(startVertex, end = ' ') - - # Recur for all the vertexes that are adjacent to this node - for i in self.vertex.keys(): - if visited[i] == False: - self.DFSRec(i, visited) - -if __name__ == '__main__': - g = Graph() - g.addEdge(0, 1) - g.addEdge(0, 2) - g.addEdge(1, 2) - g.addEdge(2, 0) - g.addEdge(2, 3) - g.addEdge(3, 3) - - g.printGraph() - print('DFS:') - g.DFS() - - # OUTPUT: - # 0  ->  1 -> 2 - # 1  ->  2 - # 2  ->  0 -> 3 - # 3  ->  3 - # DFS: - # 0 1 2 3 From 014786e340622f28cbd10dd901f1ce723cb20a19 Mon Sep 17 00:00:00 2001 From: KyleScharnhorst Date: Sat, 7 Oct 2017 06:47:50 -0700 Subject: [PATCH 12/29] Fix: typo in multiple files. --- dynamic_programming/fibonacci.py | 2 +- searches/binary_search.py | 2 +- searches/linear_search.py | 2 +- sorts/bogosort.py | 2 +- sorts/bubble_sort.py | 2 +- sorts/cocktail_shaker_sort.py | 2 +- sorts/gnome_sort.py | 2 +- sorts/insertion_sort.py | 2 +- sorts/merge_sort.py | 2 +- sorts/quick_sort.py | 2 +- sorts/selection_sort.py | 2 +- sorts/shell_sort.py | 2 +- traverals/binary_tree_traversals.py | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dynamic_programming/fibonacci.py b/dynamic_programming/fibonacci.py index 692cb756a..5eaa81b3e 100644 --- a/dynamic_programming/fibonacci.py +++ b/dynamic_programming/fibonacci.py @@ -30,7 +30,7 @@ if __name__ == '__main__': import sys print("\n********* Fibonacci Series Using Dynamic Programming ************\n") - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/searches/binary_search.py b/searches/binary_search.py index 13b54f498..ce9584aa8 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -137,7 +137,7 @@ def __assert_sorted(collection): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/searches/linear_search.py b/searches/linear_search.py index 24479e45b..ce8098b1a 100644 --- a/searches/linear_search.py +++ b/searches/linear_search.py @@ -41,7 +41,7 @@ def linear_search(sequence, target): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/bogosort.py b/sorts/bogosort.py index 2512dab51..ce1982c53 100644 --- a/sorts/bogosort.py +++ b/sorts/bogosort.py @@ -41,7 +41,7 @@ def bogosort(collection): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/bubble_sort.py b/sorts/bubble_sort.py index 54d69e5ba..d26adc89c 100644 --- a/sorts/bubble_sort.py +++ b/sorts/bubble_sort.py @@ -41,7 +41,7 @@ def bubble_sort(collection): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/cocktail_shaker_sort.py b/sorts/cocktail_shaker_sort.py index a21224632..c09d64408 100644 --- a/sorts/cocktail_shaker_sort.py +++ b/sorts/cocktail_shaker_sort.py @@ -23,7 +23,7 @@ def cocktail_shaker_sort(unsorted): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/gnome_sort.py b/sorts/gnome_sort.py index b353e31aa..4f04ff384 100644 --- a/sorts/gnome_sort.py +++ b/sorts/gnome_sort.py @@ -21,7 +21,7 @@ def gnome_sort(unsorted): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/insertion_sort.py b/sorts/insertion_sort.py index caaa9305c..33bd27c8f 100644 --- a/sorts/insertion_sort.py +++ b/sorts/insertion_sort.py @@ -41,7 +41,7 @@ def insertion_sort(collection): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/merge_sort.py b/sorts/merge_sort.py index 92a678016..ca8dbc33c 100644 --- a/sorts/merge_sort.py +++ b/sorts/merge_sort.py @@ -64,7 +64,7 @@ def merge_sort(collection): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/quick_sort.py b/sorts/quick_sort.py index 8974e1bd8..52e37b587 100644 --- a/sorts/quick_sort.py +++ b/sorts/quick_sort.py @@ -42,7 +42,7 @@ def quick_sort(ARRAY): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/selection_sort.py b/sorts/selection_sort.py index 14bc80463..752496e98 100644 --- a/sorts/selection_sort.py +++ b/sorts/selection_sort.py @@ -44,7 +44,7 @@ def selection_sort(collection): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/sorts/shell_sort.py b/sorts/shell_sort.py index fdb98a570..de3d84f72 100644 --- a/sorts/shell_sort.py +++ b/sorts/shell_sort.py @@ -45,7 +45,7 @@ def shell_sort(collection): if __name__ == '__main__': import sys - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input diff --git a/traverals/binary_tree_traversals.py b/traverals/binary_tree_traversals.py index 9cf118899..9d14a1e7e 100644 --- a/traverals/binary_tree_traversals.py +++ b/traverals/binary_tree_traversals.py @@ -84,7 +84,7 @@ if __name__ == '__main__': import sys print("\n********* Binary Tree Traversals ************\n") - # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin # otherwise 2.x's input builtin function is too "smart" if sys.version_info.major < 3: input_function = raw_input From 8fb1eb7bdf390b9f711bba02f20185f180447eca Mon Sep 17 00:00:00 2001 From: Nathan Berger Date: Mon, 9 Oct 2017 12:36:33 -0500 Subject: [PATCH 13/29] Implementation of a regression tree in python I've implemented a basic decision tree in python as an example of how they work. Although the class I've created only works on one dimensional data sets, the reader should be able to generalize it to higher dimensions should they need to. --- machine_learning/decision_tree.py | 136 ++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 machine_learning/decision_tree.py diff --git a/machine_learning/decision_tree.py b/machine_learning/decision_tree.py new file mode 100644 index 000000000..dfc2e1676 --- /dev/null +++ b/machine_learning/decision_tree.py @@ -0,0 +1,136 @@ +""" +Implementation of a basic regression decision tree. +Input data set: The input data set must be 1-dimensional with continuous labels. +Output: The decision tree maps a real number input to a real number output. +""" + +import numpy as np + +class Decision_Tree: + def __init__(self, depth = 5, min_leaf_size = 5): + self.depth = depth + self.decision_boundary = 0 + self.left = None + self.right = None + self.min_leaf_size = min_leaf_size + self.prediction = None + + def mean_squared_error(self, labels, prediction): + """ + mean_squared_error: + @param labels: a one dimensional numpy array + @param prediction: a floating point value + return value: mean_squared_error calculates the error if prediction is used to estimate the labels + """ + if labels.ndim != 1: + print("Error: Input labels must be one dimensional") + + return np.mean((labels - prediction) ** 2) + + def train(self, X, y): + """ + train: + @param X: a one dimensional numpy array + @param y: a one dimensional numpy array. + The contents of y are the labels for the corresponding X values + + train does not have a return value + """ + + """ + this section is to check that the inputs conform to our dimensionality constraints + """ + if X.ndim != 1: + print("Error: Input data set must be one dimensional") + return + if len(X) != len(y): + print("Error: X and y have different lengths") + return + if y.ndim != 1: + print("Error: Data set labels must be one dimensional") + + if len(X) < 2 * self.min_leaf_size: + self.prediction = np.mean(y) + + if self.depth == 1: + self.prediction = np.mean(y) + + best_split = 0 + min_error = self.mean_squared_error(X,np.mean(y)) * 2 + + + """ + loop over all possible splits for the decision tree. find the best split. + if no split exists that is less than 2 * error for the entire array + then the data set is not split and the average for the entire array is used as the predictor + """ + for i in range(len(X)): + if len(X[:i]) < self.min_leaf_size: + continue + elif len(X[i:]) < self.min_leaf_size: + continue + else: + error_left = self.mean_squared_error(X[:i], np.mean(y[:i])) + error_right = self.mean_squared_error(X[i:], np.mean(y[i:])) + error = error_left + error_right + if error < min_error: + best_split = i + min_error = error + + if best_split != 0: + left_X = X[:best_split] + left_y = y[:best_split] + right_X = X[best_split:] + right_y = y[best_split:] + + self.decision_boundary = X[best_split] + self.left = Decision_Tree(depth = self.depth - 1, min_leaf_size = self.min_leaf_size) + self.right = Decision_Tree(depth = self.depth - 1, min_leaf_size = self.min_leaf_size) + self.left.train(left_X, left_y) + self.right.train(right_X, right_y) + else: + self.prediction = np.mean(y) + + return + + def predict(self, x): + """ + predict: + @param x: a floating point value to predict the label of + the prediction function works by recursively calling the predict function + of the appropriate subtrees based on the tree's decision boundary + """ + if self.prediction is not None: + return self.prediction + elif self.left or self.right is not None: + if x >= self.decision_boundary: + return self.right.predict(x) + else: + return self.left.predict(x) + else: + print("Error: Decision tree not yet trained") + return None + +def main(): + """ + In this demonstration we're generating a sample data set from the sin function in numpy. + We then train a decision tree on the data set and use the decision tree to predict the + label of 10 different test values. Then the mean squared error over this test is displayed. + """ + X = np.arange(-1., 1., 0.005) + y = np.sin(X) + + tree = Decision_Tree(depth = 10, min_leaf_size = 10) + tree.train(X,y) + + test_cases = (np.random.rand(10) * 2) - 1 + predictions = np.array([tree.predict(x) for x in test_cases]) + avg_error = np.mean((predictions - test_cases) ** 2) + + print("Test values: " + str(test_cases)) + print("Predictions: " + str(predictions)) + print("Average error: " + str(avg_error)) + + +if __name__ == '__main__': + main() \ No newline at end of file From 37967bd0cf9bb8b70126d2b9d763869f327021de Mon Sep 17 00:00:00 2001 From: Nathan Berger Date: Mon, 9 Oct 2017 12:42:51 -0500 Subject: [PATCH 14/29] Fixed case where function didn't return where it should I added these return statements so that invalid inputs or valid end cases would no longer continue running through the rest of the function. --- machine_learning/decision_tree.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/machine_learning/decision_tree.py b/machine_learning/decision_tree.py index dfc2e1676..51f600cac 100644 --- a/machine_learning/decision_tree.py +++ b/machine_learning/decision_tree.py @@ -48,12 +48,15 @@ class Decision_Tree: return if y.ndim != 1: print("Error: Data set labels must be one dimensional") + return if len(X) < 2 * self.min_leaf_size: self.prediction = np.mean(y) + return if self.depth == 1: self.prediction = np.mean(y) + return best_split = 0 min_error = self.mean_squared_error(X,np.mean(y)) * 2 From cb3ff4a8f8fbcab28fc3bb08f32fcd5444886f8a Mon Sep 17 00:00:00 2001 From: fickleEfrit Date: Mon, 9 Oct 2017 17:26:27 -0400 Subject: [PATCH 15/29] Create quick_select.py --- searches/quick_select.py | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 searches/quick_select.py diff --git a/searches/quick_select.py b/searches/quick_select.py new file mode 100644 index 000000000..e5e2ce99c --- /dev/null +++ b/searches/quick_select.py @@ -0,0 +1,47 @@ +import collections +import sys +import random +import time +import math +""" +A python implementation of the quick select algorithm, which is efficient for calculating the value that would appear in the index of a list if it would be sorted, even if it is not already sorted +https://en.wikipedia.org/wiki/Quickselect +""" +def _partition(data, pivot): + """ + Three way partition the data into smaller, equal and greater lists, + in relationship to the pivot + :param data: The data to be sorted (a list) + :param pivot: The value to partition the data on + :return: Three list: smaller, equal and greater + """ + less, equal, greater = [], [], [] + for element in data: + if element.address < pivot.address: + less.append(element) + elif element.address > pivot.address: + greater.append(element) + else: + equal.append(element) + return less, equal, greater + + def quickSelect(list, k): + #k = len(list) // 2 when trying to find the median (index that value would be when list is sorted) + smaller = [] + larger = [] + pivot = random.randint(0, len(list) - 1) + pivot = list[pivot] + count = 0 + smaller, equal, larger =_partition(list, pivot) + count = len(equal) + m = len(smaller) + + #k is the pivot + if m <= k < m + count: + return pivot + # must be in smaller + elif m > k: + return quickSelect(smaller, k) + #must be in larger + else: + return quickSelect(larger, k - (m + count)) From dc5e86b7013cb02ceb0a11f32afb4a2b8f7d3ae1 Mon Sep 17 00:00:00 2001 From: Alvin Nguyen Date: Mon, 9 Oct 2017 17:00:37 -0700 Subject: [PATCH 16/29] Fixed compilation errors, fixes for readability/convention, changed double equals to boolean equality operator 'is' --- data_structures/Graph/Breadth_First_Search.py | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/data_structures/Graph/Breadth_First_Search.py b/data_structures/Graph/Breadth_First_Search.py index 1a3fdfd4d..9cb234856 100644 --- a/data_structures/Graph/Breadth_First_Search.py +++ b/data_structures/Graph/Breadth_First_Search.py @@ -1,9 +1,9 @@ class GRAPH: """docstring for GRAPH""" def __init__(self, nodes): - self.nodes=nodes - self.graph=[[0]*nodes for i in range (nodes)] - self.visited=[0]*nodes + self.nodes = nodes + self.graph = [[0]*nodes for i in range (nodes)] + self.visited = [0]*nodes def show(self): @@ -23,7 +23,7 @@ class GRAPH: v = queue[0] for u in range(self.vertex): if self.graph[v][u] == 1: - if visited[u]== False: + if visited[u] is False: visited[u] = True queue.append(u) print('%d visited' % (u +1)) @@ -41,30 +41,32 @@ g.add_edge(4,8) g.add_edge(5,9) g.add_edge(6,10) g.bfs(4) -======= - print self.graph + +print(self.graph) def add_edge(self, i, j): self.graph[i][j]=1 self.graph[j][i]=1 - def bfs(self,s): - queue=[s] - self.visited[s]=1 - while len(queue)!=0: - x=queue.pop(0) + def bfs(self, s): + queue = [s] + self.visited[s] = 1 + while len(queue)!= 0: + x = queue.pop(0) print(x) - for i in range(0,self.nodes): - if self.graph[x][i]==1 and self.visited[i]==0: + for i in range(0, self.nodes): + if self.graph[x][i] == 1 and self.visited[i] == 0: queue.append(i) - self.visited[i]=1 + self.visited[i] = 1 -n=int(input("Enter the number of Nodes : ")) -g=GRAPH(n) -e=int(input("Enter the no of edges : ")) +n = int(input("Enter the number of Nodes : ")) +g = GRAPH(n) +e = int(input("Enter the no of edges : ")) print("Enter the edges (u v)") -for i in range(0,e): - u,v=map(int, raw_input().split()) - g.add_edge(u,v) -s=int(input("Enter the source node :")) + +for i in range(0, e): + u ,v = map(int, raw_input().split()) + g.add_edge(u, v) + +s = int(input("Enter the source node :")) g.bfs(s) From ab058ab0b51486f892a1b59a22631eff5083c241 Mon Sep 17 00:00:00 2001 From: Alvin Nguyen Date: Mon, 9 Oct 2017 17:05:14 -0700 Subject: [PATCH 17/29] changed rigt->right, a typo fix. --- data_structures/Binary Tree/binary_seach_tree.py | 6 +++--- data_structures/Graph/Breadth_First_Search.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data_structures/Binary Tree/binary_seach_tree.py b/data_structures/Binary Tree/binary_seach_tree.py index 1dac948ae..0b1726534 100644 --- a/data_structures/Binary Tree/binary_seach_tree.py +++ b/data_structures/Binary Tree/binary_seach_tree.py @@ -8,7 +8,7 @@ class Node: def __init__(self, label): self.label = label self.left = None - self.rigt = None + self.right = None def getLabel(self): return self.label @@ -23,10 +23,10 @@ class Node: self.left = left def getRight(self): - return self.rigt + return self.right def setRight(self, right): - self.rigt = right + self.right = right class BinarySearchTree: diff --git a/data_structures/Graph/Breadth_First_Search.py b/data_structures/Graph/Breadth_First_Search.py index 9cb234856..92a6e819b 100644 --- a/data_structures/Graph/Breadth_First_Search.py +++ b/data_structures/Graph/Breadth_First_Search.py @@ -67,6 +67,6 @@ print("Enter the edges (u v)") for i in range(0, e): u ,v = map(int, raw_input().split()) g.add_edge(u, v) - + s = int(input("Enter the source node :")) g.bfs(s) From 8f71b309953fec9da78ef64ea8cc2e7314ec1b6f Mon Sep 17 00:00:00 2001 From: TaylorL19 Date: Tue, 10 Oct 2017 11:57:16 -0500 Subject: [PATCH 18/29] Fixed binary search to correctly recurse to left half and right half --- searches/binary_search.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/searches/binary_search.py b/searches/binary_search.py index 13b54f498..8dc3008da 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -110,9 +110,9 @@ def binary_search_by_recursion(sorted_collection, item, left, right): if sorted_collection[midpoint] == item: return midpoint elif sorted_collection[midpoint] > item: - return binary_search_by_recursion(sorted_collection, item, left, right-1) + return binary_search_by_recursion(sorted_collection, item, left, midpoint-1) else: - return binary_search_by_recursion(sorted_collection, item, left+1, right) + return binary_search_by_recursion(sorted_collection, item, midpoint+1, right) def __assert_sorted(collection): """Check if collection is sorted, if not - raises :py:class:`ValueError` From a07baadf04d3b1db9051f2ed2353abc83b35a732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kilian=20Rue=C3=9F?= Date: Thu, 12 Oct 2017 21:35:23 +0200 Subject: [PATCH 19/29] Added fastfibonacci.py --- dynamic_programming/fastfibonacci.py | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 dynamic_programming/fastfibonacci.py diff --git a/dynamic_programming/fastfibonacci.py b/dynamic_programming/fastfibonacci.py new file mode 100644 index 000000000..5957fbe0d --- /dev/null +++ b/dynamic_programming/fastfibonacci.py @@ -0,0 +1,42 @@ +""" +This program calculates the nth Fibonacci number in O(log(n)). +It's possible to calculate F(1000000) in less than a second. +""" +import sys + + +# returns F(n) +def fibonacci(n: int): + if n < 0: + raise ValueError("Negative arguments are not supported") + return _fib(n)[0] + + +# returns (F(n), F(n-1)) +def _fib(n: int): + if n == 0: + # (F(0), F(1)) + return (0, 1) + else: + # F(2n) = F(n)[2F(n+1) − F(n)] + # F(2n+1) = F(n+1)^2+F(n)^2 + a, b = _fib(n // 2) + c = a * (b * 2 - a) + d = a * a + b * b + if n % 2 == 0: + return (c, d) + else: + return (d, c + d) + + +if __name__ == "__main__": + args = sys.argv[1:] + if len(args) != 1: + print("Too few or too much parameters given.") + exit(1) + try: + n = int(args[0]) + except ValueError: + print("Could not convert data to an integer.") + exit(1) + print("F(%d) = %d" % (n, fibonacci(n))) From 86a5b0345fdbdf9931f00a26d80c61f6cf23c957 Mon Sep 17 00:00:00 2001 From: Corey Hu Date: Thu, 12 Oct 2017 23:56:14 -0700 Subject: [PATCH 20/29] Recursive solution to insert_tail in singly_LinkedList --- .../LinkedList/singly_LinkedList.py | 37 +++++++------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/data_structures/LinkedList/singly_LinkedList.py b/data_structures/LinkedList/singly_LinkedList.py index 941e8a0fa..c9a3cec27 100644 --- a/data_structures/LinkedList/singly_LinkedList.py +++ b/data_structures/LinkedList/singly_LinkedList.py @@ -3,22 +3,15 @@ class Node:#create a Node self.data=data#given data self.next=None#given next to None class Linked_List: + pass - def insert_tail(Head,data):#insert the data at tail - tamp=Head#create a tamp as a head - if(tamp==None):#if linkedlist is empty - newNod=Node()#create newNode Node type and given data and next - newNod.data=data - newNod.next=None - Head=newNod + + def insert_tail(Head,data): + if(Head.next is None): + Head.next = Node(data) else: - while tamp.next!=None:#find the last Node - tamp=tamp.next - newNod = Node()#create a new node - newNod.data = data - newNod.next = None - tamp.next=newNod#put the newnode into last node - return Head#return first node of linked list + insert_tail(Head.next, data) + def insert_head(Head,data): tamp = Head if (tamp == None): @@ -32,16 +25,18 @@ class Linked_List: newNod.next = Head#put the Head at NewNode Next Head=newNod#make a NewNode to Head return Head - def Print(Head):#print every node data - tamp=Node() + + def printList(Head):#print every node data tamp=Head while tamp!=None: print(tamp.data) tamp=tamp.next + def delete_head(Head):#delete from head if Head!=None: Head=Head.next return Head#return new Head + def delete_tail(Head):#delete from tail if Head!=None: tamp = Node() @@ -50,12 +45,6 @@ class Linked_List: tamp = tamp.next tamp.next=None#delete the last element by give next None to 2nd last Element return Head + def isEmpty(Head): - if(Head==None):#check Head is None or Not - return True#return Ture if list is empty - else: - return False#check False if it's not empty - - - - + return Head is None #Return if Head is none \ No newline at end of file From e0211794da527caaa0e3621fa4a8ae60eed3c547 Mon Sep 17 00:00:00 2001 From: nandujkishor Date: Fri, 13 Oct 2017 20:33:40 +0530 Subject: [PATCH 21/29] Changed the typographical error (#132) Changed the typo in line 113 and 115 regarding recursive binary search algorithm, found by a user who commented in comments. --- searches/binary_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searches/binary_search.py b/searches/binary_search.py index 8dc3008da..5ef0a0321 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -113,7 +113,7 @@ def binary_search_by_recursion(sorted_collection, item, left, right): return binary_search_by_recursion(sorted_collection, item, left, midpoint-1) else: return binary_search_by_recursion(sorted_collection, item, midpoint+1, right) - + def __assert_sorted(collection): """Check if collection is sorted, if not - raises :py:class:`ValueError` From 81ab3249d418396a3f7e8d35514e9fe8c9bb412b Mon Sep 17 00:00:00 2001 From: Sachin Arora Date: Fri, 13 Oct 2017 20:45:39 +0530 Subject: [PATCH 22/29] Revert "There were 2 codes for BFS and DFS in data-structure/Graph." (#163) --- .../Graph/P01_BreadthFirstSearch.py | 61 +++++++++++++++++++ data_structures/Graph/P02_DepthFirstSearch.py | 61 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 data_structures/Graph/P01_BreadthFirstSearch.py create mode 100644 data_structures/Graph/P02_DepthFirstSearch.py diff --git a/data_structures/Graph/P01_BreadthFirstSearch.py b/data_structures/Graph/P01_BreadthFirstSearch.py new file mode 100644 index 000000000..16b1b2007 --- /dev/null +++ b/data_structures/Graph/P01_BreadthFirstSearch.py @@ -0,0 +1,61 @@ +# Author: OMKAR PATHAK + +class Graph(): + def __init__(self): + self.vertex = {} + + # for printing the Graph vertexes + def printGraph(self): + for i in self.vertex.keys(): + print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) + + # for adding the edge beween two vertexes + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present, + if fromVertex in self.vertex.keys(): + self.vertex[fromVertex].append(toVertex) + else: + # else make a new vertex + self.vertex[fromVertex] = [toVertex] + + def BFS(self, startVertex): + # Take a list for stoting already visited vertexes + visited = [False] * len(self.vertex) + + # create a list to store all the vertexes for BFS + queue = [] + + # mark the source node as visited and enqueue it + visited[startVertex] = True + queue.append(startVertex) + + while queue: + startVertex = queue.pop(0) + print(startVertex, end = ' ') + + # mark all adjacent nodes as visited and print them + for i in self.vertex[startVertex]: + if visited[i] == False: + queue.append(i) + visited[i] = True + +if __name__ == '__main__': + g = Graph() + g.addEdge(0, 1) + g.addEdge(0, 2) + g.addEdge(1, 2) + g.addEdge(2, 0) + g.addEdge(2, 3) + g.addEdge(3, 3) + + g.printGraph() + print('BFS:') + g.BFS(2) + + # OUTPUT: + # 0  ->  1 -> 2 + # 1  ->  2 + # 2  ->  0 -> 3 + # 3  ->  3 + # BFS: + # 2 0 3 1 diff --git a/data_structures/Graph/P02_DepthFirstSearch.py b/data_structures/Graph/P02_DepthFirstSearch.py new file mode 100644 index 000000000..94ef3cb86 --- /dev/null +++ b/data_structures/Graph/P02_DepthFirstSearch.py @@ -0,0 +1,61 @@ +# Author: OMKAR PATHAK + +class Graph(): + def __init__(self): + self.vertex = {} + + # for printing the Graph vertexes + def printGraph(self): + print(self.vertex) + for i in self.vertex.keys(): + print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) + + # for adding the edge beween two vertexes + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present, + if fromVertex in self.vertex.keys(): + self.vertex[fromVertex].append(toVertex) + else: + # else make a new vertex + self.vertex[fromVertex] = [toVertex] + + def DFS(self): + # visited array for storing already visited nodes + visited = [False] * len(self.vertex) + + # call the recursive helper function + for i in range(len(self.vertex)): + if visited[i] == False: + self.DFSRec(i, visited) + + def DFSRec(self, startVertex, visited): + # mark start vertex as visited + visited[startVertex] = True + + print(startVertex, end = ' ') + + # Recur for all the vertexes that are adjacent to this node + for i in self.vertex.keys(): + if visited[i] == False: + self.DFSRec(i, visited) + +if __name__ == '__main__': + g = Graph() + g.addEdge(0, 1) + g.addEdge(0, 2) + g.addEdge(1, 2) + g.addEdge(2, 0) + g.addEdge(2, 3) + g.addEdge(3, 3) + + g.printGraph() + print('DFS:') + g.DFS() + + # OUTPUT: + # 0  ->  1 -> 2 + # 1  ->  2 + # 2  ->  0 -> 3 + # 3  ->  3 + # DFS: + # 0 1 2 3 From 974acef310bc70dc634b651d9e8ea502ae09ad04 Mon Sep 17 00:00:00 2001 From: Sachin Arora Date: Fri, 13 Oct 2017 21:03:16 +0530 Subject: [PATCH 23/29] Deleting duplicate BFS and DFS files. (#164) * Deleting duplicate file BFS. * deleting duplicate file DFS. * Rename P01_BreadthFirstSearch.py to BreadthFirstSearch.py * Rename P02_DepthFirstSearch.py to DepthFirstSearch.py --- ...thFirstSearch.py => BreadthFirstSearch.py} | 0 data_structures/Graph/Breadth_First_Search.py | 72 ------------------- data_structures/Graph/Deep_First_Search.py | 32 --------- ...epthFirstSearch.py => DepthFirstSearch.py} | 0 4 files changed, 104 deletions(-) rename data_structures/Graph/{P01_BreadthFirstSearch.py => BreadthFirstSearch.py} (100%) delete mode 100644 data_structures/Graph/Breadth_First_Search.py delete mode 100644 data_structures/Graph/Deep_First_Search.py rename data_structures/Graph/{P02_DepthFirstSearch.py => DepthFirstSearch.py} (100%) diff --git a/data_structures/Graph/P01_BreadthFirstSearch.py b/data_structures/Graph/BreadthFirstSearch.py similarity index 100% rename from data_structures/Graph/P01_BreadthFirstSearch.py rename to data_structures/Graph/BreadthFirstSearch.py diff --git a/data_structures/Graph/Breadth_First_Search.py b/data_structures/Graph/Breadth_First_Search.py deleted file mode 100644 index 92a6e819b..000000000 --- a/data_structures/Graph/Breadth_First_Search.py +++ /dev/null @@ -1,72 +0,0 @@ -class GRAPH: - """docstring for GRAPH""" - def __init__(self, nodes): - self.nodes = nodes - self.graph = [[0]*nodes for i in range (nodes)] - self.visited = [0]*nodes - - - def show(self): - - for i in self.graph: - for j in i: - print(j, end=' ') - print(' ') - def bfs(self,v): - - visited = [False]*self.vertex - visited[v - 1] = True - print('%d visited' % (v)) - - queue = [v - 1] - while len(queue) > 0: - v = queue[0] - for u in range(self.vertex): - if self.graph[v][u] == 1: - if visited[u] is False: - visited[u] = True - queue.append(u) - print('%d visited' % (u +1)) - queue.pop(0) - -g = Graph(10) - -g.add_edge(1,2) -g.add_edge(1,3) -g.add_edge(1,4) -g.add_edge(2,5) -g.add_edge(3,6) -g.add_edge(3,7) -g.add_edge(4,8) -g.add_edge(5,9) -g.add_edge(6,10) -g.bfs(4) - -print(self.graph) - - def add_edge(self, i, j): - self.graph[i][j]=1 - self.graph[j][i]=1 - - def bfs(self, s): - queue = [s] - self.visited[s] = 1 - while len(queue)!= 0: - x = queue.pop(0) - print(x) - for i in range(0, self.nodes): - if self.graph[x][i] == 1 and self.visited[i] == 0: - queue.append(i) - self.visited[i] = 1 - -n = int(input("Enter the number of Nodes : ")) -g = GRAPH(n) -e = int(input("Enter the no of edges : ")) -print("Enter the edges (u v)") - -for i in range(0, e): - u ,v = map(int, raw_input().split()) - g.add_edge(u, v) - -s = int(input("Enter the source node :")) -g.bfs(s) diff --git a/data_structures/Graph/Deep_First_Search.py b/data_structures/Graph/Deep_First_Search.py deleted file mode 100644 index 656ddfbaf..000000000 --- a/data_structures/Graph/Deep_First_Search.py +++ /dev/null @@ -1,32 +0,0 @@ -class GRAPH: - """docstring for GRAPH""" - def __init__(self, nodes): - self.nodes=nodes - self.graph=[[0]*nodes for i in range (nodes)] - self.visited=[0]*nodes - - - def show(self): - print self.graph - - def add_edge(self, i, j): - self.graph[i][j]=1 - self.graph[j][i]=1 - - def dfs(self,s): - self.visited[s]=1 - print(s) - for i in range(0,self.nodes): - if self.visited[i]==0 and self.graph[s][i]==1: - self.dfs(i) - - -n=int(input("Enter the number of Nodes : ")) -g=GRAPH(n) -e=int(input("Enter the no of edges : ")) -print("Enter the edges (u v)") -for i in range(0,e): - u,v=map(int, raw_input().split()) - g.add_edge(u,v) -s=int(input("Enter the source node :")) -g.dfs(s) diff --git a/data_structures/Graph/P02_DepthFirstSearch.py b/data_structures/Graph/DepthFirstSearch.py similarity index 100% rename from data_structures/Graph/P02_DepthFirstSearch.py rename to data_structures/Graph/DepthFirstSearch.py From 35d38737168ebfe4eb54e829f98dc31296aa52dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Sat, 14 Oct 2017 03:07:02 +0000 Subject: [PATCH 24/29] Add counting sort --- sorts/counting_sort.py | 72 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 sorts/counting_sort.py diff --git a/sorts/counting_sort.py b/sorts/counting_sort.py new file mode 100644 index 000000000..13e4554ae --- /dev/null +++ b/sorts/counting_sort.py @@ -0,0 +1,72 @@ +""" +This is pure python implementation of counting sort algorithm +For doctests run following command: +python -m doctest -v counting_sort.py +or +python3 -m doctest -v counting_sort.py +For manual testing run: +python counting_sort.py +""" + +from __future__ import print_function + + +def counting_sort(collection): + """Pure implementation of counting sort algorithm in Python + :param collection: some mutable ordered collection with heterogeneous + comparable items inside + :return: the same collection ordered by ascending + Examples: + >>> counting_sort([0, 5, 3, 2, 2]) + [0, 2, 2, 3, 5] + >>> counting_sort([]) + [] + >>> counting_sort([-2, -5, -45]) + [-45, -5, -2] + """ + # if the collection is empty, returns empty + if collection == []: + return [] + + # get some information about the collection + coll_len = len(collection) + coll_max = max(collection) + coll_min = min(collection) + + # create the counting array + counting_arr_length = coll_max + 1 - coll_min + counting_arr = [0] * counting_arr_length + + # count how much a number appears in the collection + for number in collection: + counting_arr[number - coll_min] += 1 + + # sum each position with it's predecessors. now, counting_arr[i] tells + # us how many elements <= i has in the collection + for i in range(1, counting_arr_length): + counting_arr[i] = counting_arr[i] + counting_arr[i-1] + + # create the output collection + ordered = [0] * coll_len + + # place the elements in the output, respecting the original order (stable + # sort) from end to begin, updating counting_arr + for i in reversed(range(0, coll_len)): + ordered[counting_arr[collection[i] - coll_min]-1] = collection[i] + counting_arr[collection[i] - coll_min] -= 1 + + return ordered + + +if __name__ == '__main__': + import sys + # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin + # otherwise 2.x's input builtin function is too "smart" + if sys.version_info.major < 3: + input_function = raw_input + else: + input_function = input + + user_input = input_function('Enter numbers separated by a comma:\n') + unsorted = [int(item) for item in user_input.split(',')] + print(counting_sort(unsorted)) From eb8375d13801eb812a76aa689b062a4d66d410ea Mon Sep 17 00:00:00 2001 From: Harshil Date: Sat, 14 Oct 2017 09:54:52 +0530 Subject: [PATCH 25/29] Commented travis tag Commented travis tag untill we find suitable travis.yml --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9589bccd9..d77e17e75 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# The Algorithms - Python [![Build Status](https://travis-ci.org/TheAlgorithms/Python.svg)](https://travis-ci.org/TheAlgorithms/Python) +# The Algorithms - Python ### All algorithms implemented in Python (for education) From d7fccf50690f84e0e3072b3c0fc7e159031078e8 Mon Sep 17 00:00:00 2001 From: yeggasd Date: Sun, 15 Oct 2017 00:44:53 +0800 Subject: [PATCH 26/29] Updated README.md Added Vigenere Cipher description --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index d77e17e75..70077e98f 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,13 @@ The method is named after **Julius Caesar**, who used it in his private correspo The encryption step performed by a Caesar cipher is often incorporated as part of more complex schemes, such as the Vigenère cipher, and still has modern application in the ROT13 system. As with all single-alphabet substitution ciphers, the Caesar cipher is easily broken and in modern practice offers essentially no communication security. ###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher) +### Vigenère +The **Vigenère cipher** is a method of encrypting alphabetic text by using a series of **interwoven Caesar ciphers** based on the letters of a keyword. It is **a form of polyalphabetic substitution**.
+The Vigenère cipher has been reinvented many times. The method was originally described by Giovan Battista Bellaso in his 1553 book La cifra del. Sig. Giovan Battista Bellaso; however, the scheme was later misattributed to Blaise de Vigenère in the 19th century, and is now widely known as the "Vigenère cipher".
+Though the cipher is easy to understand and implement, for three centuries it resisted all attempts to break it; this earned it the description **le chiffre indéchiffrable**(French for 'the indecipherable cipher'). +Many people have tried to implement encryption schemes that are essentially Vigenère ciphers. Friedrich Kasiski was the first to publish a general method of deciphering a Vigenère cipher in 1863. +###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher) + ### Transposition In cryptography, a **transposition cipher** is a method of encryption by which the positions held by units of plaintext (which are commonly characters or groups of characters) are shifted according to a regular system, so that the ciphertext constitutes a permutation of the plaintext. That is, the order of the units is changed (the plaintext is reordered).
Mathematically a bijective function is used on the characters' positions to encrypt and an inverse function to decrypt. From d70b9268fe2d05f5ff6197b957b98f935fb13e91 Mon Sep 17 00:00:00 2001 From: Sarbajit Saha Date: Sun, 15 Oct 2017 21:25:54 +0530 Subject: [PATCH 27/29] fixed spelling of coma to comma --- searches/binary_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searches/binary_search.py b/searches/binary_search.py index 340649e4f..c54aa96a1 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -144,7 +144,7 @@ if __name__ == '__main__': else: input_function = input - user_input = input_function('Enter numbers separated by coma:\n') + user_input = input_function('Enter numbers separated by comma:\n') collection = [int(item) for item in user_input.split(',')] try: __assert_sorted(collection) From 6d192700c686a9d432c7ec0369fcc0cacb5875bd Mon Sep 17 00:00:00 2001 From: Sarbajit Saha Date: Sun, 15 Oct 2017 21:41:10 +0530 Subject: [PATCH 28/29] added interpolation search --- searches/interpolation_search.py | 102 +++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 searches/interpolation_search.py diff --git a/searches/interpolation_search.py b/searches/interpolation_search.py new file mode 100644 index 000000000..068d9c554 --- /dev/null +++ b/searches/interpolation_search.py @@ -0,0 +1,102 @@ +""" +This is pure python implementation of interpolation search algorithm +""" +from __future__ import print_function +import bisect + + +def interpolation_search(sorted_collection, item): + """Pure implementation of interpolation search algorithm in Python + Be careful collection must be sorted, otherwise result will be + unpredictable + :param sorted_collection: some sorted collection with comparable items + :param item: item value to search + :return: index of found item or None if item is not found + """ + left = 0 + right = len(sorted_collection) - 1 + + while left <= right: + point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left]) + + #out of range check + if point<0 or point>=len(sorted_collection): + return None + + current_item = sorted_collection[point] + if current_item == item: + return point + else: + if item < current_item: + right = point - 1 + else: + left = point + 1 + return None + + +def interpolation_search_by_recursion(sorted_collection, item, left, right): + + """Pure implementation of interpolation search algorithm in Python by recursion + Be careful collection must be sorted, otherwise result will be + unpredictable + First recursion should be started with left=0 and right=(len(sorted_collection)-1) + :param sorted_collection: some sorted collection with comparable items + :param item: item value to search + :return: index of found item or None if item is not found + """ + point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left]) + + #out of range check + if point<0 or point>=len(sorted_collection): + return None + + if sorted_collection[point] == item: + return point + elif sorted_collection[point] > item: + return interpolation_search_by_recursion(sorted_collection, item, left, point-1) + else: + return interpolation_search_by_recursion(sorted_collection, item, point+1, right) + +def __assert_sorted(collection): + """Check if collection is sorted, if not - raises :py:class:`ValueError` + :param collection: collection + :return: True if collection is sorted + :raise: :py:class:`ValueError` if collection is not sorted + Examples: + >>> __assert_sorted([0, 1, 2, 4]) + True + >>> __assert_sorted([10, -1, 5]) + Traceback (most recent call last): + ... + ValueError: Collection must be sorted + """ + if collection != sorted(collection): + raise ValueError('Collection must be sorted') + return True + + +if __name__ == '__main__': + import sys + # For python 2.x and 3.x compatibility: 3.x has no raw_input builtin + # otherwise 2.x's input builtin function is too "smart" + if sys.version_info.major < 3: + input_function = raw_input + else: + input_function = input + + user_input = input_function('Enter numbers separated by comma:\n') + collection = [int(item) for item in user_input.split(',')] + try: + __assert_sorted(collection) + except ValueError: + sys.exit('Sequence must be sorted to apply interpolation search') + + target_input = input_function( + 'Enter a single number to be found in the list:\n' + ) + target = int(target_input) + result = interpolation_search(collection, target) + if result is not None: + print('{} found at positions: {}'.format(target, result)) + else: + print('Not found') \ No newline at end of file From cf7d2cbec6cf29d1bbb455ac2366746a0605441a Mon Sep 17 00:00:00 2001 From: agdenadel Date: Mon, 16 Oct 2017 20:20:00 -0400 Subject: [PATCH 29/29] Fix typo in traversals --- {traverals => traversals}/binary_tree_traversals.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {traverals => traversals}/binary_tree_traversals.py (100%) diff --git a/traverals/binary_tree_traversals.py b/traversals/binary_tree_traversals.py similarity index 100% rename from traverals/binary_tree_traversals.py rename to traversals/binary_tree_traversals.py