def _extract_patches(self,X):
     
     ag.info('Extract Patches: Seperate coded regions into groups')
     trainingDataNum = X.shape[0]
     totalRange = X.shape[1]
     frame = (self._part_shape[0] - self._lowerLayerShape[0]) / 2
     frame = int(frame)
     partsRegion = [[] for x in range(self._num_lower_parts//self._rotation)]
     
     
     for i in range(trainingDataNum):
         for m in range(totalRange)[frame:totalRange - frame]:
             for n in range(totalRange)[frame:totalRange - frame]:
                 if(X[i,m,n]!=-1):
                     partsGrid = X[i,m-frame:m+frame+1,n-frame:n+frame+1]
                     detectedIndex = X[i,m,n]
                     uprightIndex = (detectedIndex - detectedIndex % self._rotation)//self._rotation
                     partsRegion[uprightIndex].append(partsGrid)
     finalResultRegion = []
     for i in range(self._num_lower_parts//self._rotation):
         blocks = []
         for ori in range(self._rotation):
             angle = ori / self._rotation * 360
             from pnet.cyfuncs import rotate_index_map_pooling
             yy1 = rotate_index_map_pooling(np.asarray(partsRegion[i]),angle, 0, self._rotation, self._num_lower_parts, (self._part_shape[0] - self._lowerLayerShape[0] + 1,self._part_shape[1] - self._lowerLayerShape[1] + 1))
             #yy.shape = (numOfPatches, 1, 1, rotation, trueParts)
             yy = yy1.reshape(yy1.shape[:3] + (self._rotation, self._num_lower_parts // self._rotation))
             blocks.append(yy)
         #blocks.shape = (numofPatches, numOfRotations, 1, 1, rotation, trueParts)
         blocks = np.asarray(blocks).transpose((1,0,2,3,4,5))
         shape = blocks.shape[2:4] + (np.prod(blocks.shape[4:]),)
         ## Flatten
         blocks = blocks.reshape(blocks.shape[:2] + (-1,))
         finalResultRegion.append(blocks)
     return (finalResultRegion, shape)
    def _train(self, phi, data, y):
        X_n = phi(data)
        X = X_n[0]
        num_parts = X_n[1]
        num_orientations = X_n[2]
        num_true_parts = num_parts // num_orientations

        self._extra['training_comp'] = []

        K = int(y.max()) + 1

        mm_models = []

        for k in range(K):
            Xk = X[y == k]
            assert Xk.shape[-1] == 1

            from pnet.cyfuncs import index_map_pooling_multi

            # Rotate all the Xk samples

            print('A')
            XB = index_map_pooling_multi(Xk, num_parts, (1, 1), (1, 1))
            print('B')
            XB = XB.reshape(XB.shape[:-1] + (num_true_parts, num_orientations))

            blocks = []

            print('C')
            for ori in range(0, self._n_orientations):
                angle = ori / self._n_orientations * 360
                # Rotate all images, apply rotational spreading, then do
                # pooling

                from pnet.cyfuncs import rotate_index_map_pooling

                sr = self._pooling_settings.get('rotation_spreading_radius', 0)
                yy1 = rotate_index_map_pooling(Xk[..., 0], angle, sr,
                                               num_orientations,
                                               num_parts,
                                               self._pooling_settings['shape'])

                sh = yy1.shape[:3] + (num_orientations, num_true_parts)
                yy = yy1.reshape(sh)

                blocks.append(yy)

            blocks = np.asarray(blocks).transpose((1, 0, 2, 3, 4, 5))
            print('D')

            """
            from pnet.vzlog import default as vz

            import gv

            for i in range(self._n_orientations):
                gv.img.save_image(vz.impath(), blocks[0, i, :, :, 0].sum(-1))

            vz.finalize()
            """

            shape = blocks.shape[2:4] + (np.prod(blocks.shape[4:]),)

            # Flatten
            blocks = blocks.reshape(blocks.shape[:2] + (-1,))

            n_init = self._settings.get('n_init', 1)
            n_iter = self._settings.get('n_iter', 10)
            seed = self._settings.get('seed', 0)

            ORI = self._n_orientations
            POL = 1

            def cycles(X):
                return np.asarray([np.concatenate([X[i:], X[:i]])
                                   for i in range(len(X))])

            RR = np.arange(ORI)
            PP = np.arange(POL)
            II = [list(itr.product(PPi, RRi))
                  for PPi in cycles(PP)
                  for RRi in cycles(RR)]
            lookup = dict(zip(itr.product(PP, RR), itr.count()))
            permutations = [[lookup[ii] for ii in rows] for rows in II]
            permutations = np.asarray(permutations)

            print('E')

            if 1:
                mm = PermutationMM(n_components=self._n_components,
                                   permutations=permutations,
                                   n_iter=n_iter,
                                   n_init=n_init,
                                   random_state=seed,
                                   min_probability=self._min_prob)
                mm.fit(blocks)
                comps = mm.predict(blocks)
                mu_shape = (self._n_components * self._n_orientations,) + shape
                mu = mm.means_.reshape(mu_shape)

            else:
                num_angle = self._n_orientations
                d = np.prod(shape)
                sh = (num_angle, num_angle * d)
                permutation = np.empty(sh, dtype=np.int_)
                for a in range(num_angle):
                    if a == 0:
                        permutation[a] = np.arange(num_angle * d)
                    else:
                        permutation[a] = np.roll(permutation[a-1], -d)

                from pnet.bernoulli import em


                XX = blocks.reshape((blocks.shape[0], -1))
                print('F Digit:', d)
                ret = em(XX, self._n_components, n_iter,
                         permutation=permutation, numpy_rng=seed,
                         verbose=True)
                print('G')

                comps = ret[3]

                self._extra['training_comp'].append(ret[3])

                mu = ret[1].reshape((self._n_components * self._n_orientations,) + shape)

            if 0: # Build visualizations of all rotations

                ims10k = self._data
                label10k = y

                ims10k_d = ims10k[label10k == d]

                rot_ims10k = np.asarray([[rotate(im, -rot, resize=False) for rot in np.arange(n_orientations) * 360 / n_orientations] for im in ims10k_d])

                vispart_blocks = []

                for phase in range(n_orientations):
                    visparts = np.asarray([
                        rot_ims10k[comps[:, 0]==k, comps[comps[:, 0]==k][:, 1]].mean(0) for k in range(n_comp)
                    ])

                    M = 50

                    grid0 = pnet.plot.ImageGrid(n_comp, min(M, np.max(map(len, XX))), ims10k.shape[1:])
                    for k in range(n_comp):
                        for i in range(min(M, len(XX[k]))):
                            grid0.set_image(XX[k][i], k, i, vmin=0, vmax=1, cmap=cm.gray)
                    grid0.save(vz.impath(), scale=3)

                    for k in range(n_comp):
                        grid.set_image(visparts[k], d, k, vmin=0, vmax=1, cmap=cm.gray)




            mm_models.append(mu)
            print('H')


        self._models = np.asarray(mm_models)
    def train(self, X_n, Y, OriginalX = None):
        X = X_n[0]
        num_parts = X_n[1]
        if(len(X_n) == 3):
            num_orientations = X_n[2]
        else:
            num_orientations = 1
        num_true_parts = num_parts // num_orientations

        self._extra['training_comp'] = []

        K = Y.max() + 1

        mm_models = []
        print(X.shape)
        for k in xrange(K):
            Xk = X[Y == k]

            assert Xk.shape[-1] == 1


            from pnet.cyfuncs import index_map_pooling_multi, orientation_pooling

            # Rotate all the Xk samples

            print('A')
            XB = index_map_pooling_multi(Xk, num_parts, (1, 1), (1, 1))
            print('B')
            XB = XB.reshape(XB.shape[:-1] + (num_true_parts, num_orientations))

            blocks = [] 

            print('C')
            for ori in xrange(0, self._n_orientations):
                angle = ori / self._n_orientations * 360
                # Rotate all images, apply rotational spreading, then do pooling

                if 0:
                    print(ori, 'R{')
                    rots = np.asarray([rotate_patch_map(XB[i], angle) for i in xrange(XB.shape[0])])
                    print(ori, 'R}')


                    print(ori, 'P{')
                    yy = orientation_pooling(rots, 
                                             self._pooling_settings['shape'],
                                             self._pooling_settings['strides'],
                                             self._pooling_settings.get('rotation_spreading_radius', 0))
                    print(ori, 'P}')

                from pnet.cyfuncs import rotate_index_map_pooling 


                if num_orientations !=1:
                    yy1 = rotate_index_map_pooling(Xk[...,0], angle, self._pooling_settings.get('rotation_spreading_radius', 0),
                                               num_orientations, 
                                               num_parts,
                                               self._pooling_settings['shape'])
                else:
                    from pnet.cyfuncs import index_map_pooling_multi as poolf
                    print(Xk.shape)
                    yy1 = poolf(Xk,num_parts,self._pooling_settings.get('shape'), self._pooling_settings.get('strides')) 
                print(yy1.shape, num_orientations, num_true_parts)
                yy = yy1.reshape(yy1.shape[:3] + (num_orientations, num_true_parts))
                blocks.append(yy)#.reshape(yy.shape[:-2] + (-1,)))

            blocks = np.asarray(blocks).transpose((1, 0, 2, 3, 4, 5))
            print('D')

            if 0:
                from pnet.vzlog import default as vz

                import gv

                for i in xrange(self._n_orientations):
                    gv.img.save_image(vz.generate_filename(), blocks[0,i,:,:,0].sum(-1))

                vz.finalize()

            shape = blocks.shape[2:4] + (np.prod(blocks.shape[4:]),)

            # Flatten
            blocks = blocks.reshape(blocks.shape[:2] + (-1,))

            n_init = self._settings.get('n_init', 1)
            n_iter = self._settings.get('n_iter', 10)
            seed = self._settings.get('em_seed', 0)

            ORI = self._n_orientations
            POL = 1

            P = ORI * POL


            def cycles(X):
                return np.asarray([np.concatenate([X[i:], X[:i]]) for i in xrange(len(X))])

            RR = np.arange(ORI)
            PP = np.arange(POL)
            II = [list(itr.product(PPi, RRi)) for PPi in cycles(PP) for RRi in cycles(RR)]
            lookup = dict(zip(itr.product(PP, RR), itr.count()))
            permutations = np.asarray([[lookup[ii] for ii in rows] for rows in II])

            print('E')

            if 0:
                mm = PermutationMM(n_components=self._n_components, 
                                   permutations=permutations,
                                   n_iter=n_iter, 
                                   n_init=n_init, 
                                   random_state=seed, 
                                   min_probability=self._min_prob)
                mm.fit(blocks)
                mu = mm.means_.reshape((self._n_components,)+shape)

            else:       
                num_angle = self._n_orientations
                d = np.prod(shape)
                permutation = np.empty((num_angle, num_angle * d), dtype=np.int_)
                for a in range(num_angle):
                    if a == 0:
                        permutation[a] = np.arange(num_angle * d)
                    else:
                        permutation[a] = np.roll(permutation[a-1], -d)

                from pnet.bernoulli import em      


                XX = blocks.reshape((blocks.shape[0], -1))
                print('F')
                ret = em(XX, self._n_components, n_iter,
                         permutation=permutation, numpy_rng=seed,
                         verbose=True)
                print('G')

                self._extra['training_comp'].append(ret[3])

                mu = ret[1].reshape((self._n_components * self._n_orientations,) + shape)


            
            mm_models.append(mu)
            print('H')


        self._models = np.asarray(mm_models)