コード例 #1
0
    def check_representation(self, repr: Representation):
    
        group = repr.group
        
        np.set_printoptions(precision=2, threshold=2 * repr.size ** 2, suppress=True,
                            linewidth=10 * repr.size + 3)
        
        P = directsum([group.irreps[irr] for irr in repr.irreps], name="irreps")
        
        self.assertTrue(np.allclose(repr.change_of_basis @ repr.change_of_basis.T, np.eye(repr.size)))
        self.assertTrue(np.allclose(repr.change_of_basis.T @ repr.change_of_basis, np.eye(repr.size)))
        
        for a in group.testing_elements():
            
            repr_1 = repr(a)
            repr_2 = repr.change_of_basis @ P(a) @ repr.change_of_basis_inv

            self.assertTrue(np.allclose(repr_1, repr_2),
                            msg=f"{a}:\n{repr_1}\ndifferent from\n {repr_2}\n")
            
            for b in group.testing_elements():
                repr_ab = repr(a) @ repr(b)
                c = group.combine(a, b)
                repr_c = repr(c)

                self.assertTrue(np.allclose(repr_ab, repr_c), msg=f"{a} x {b} = {c}:\n{repr_ab}\ndifferent from\n {repr_c}\n")
コード例 #2
0
    def test_mix_o2(self):
        g = O2(6)
        rr = directsum(list(g.representations.values()))
    
        N = 3
        size = rr.size * N

        bcob = ortho_group.rvs(dim=size//5)
        bsize = bcob.shape[0]
        p = np.eye(size, size)

        for i in range(size//bsize):
            p[i*bsize:(i+1)*bsize, i*bsize:(i+1)*bsize] = bcob
        p = p[:, np.random.permutation(size)]
        repr = directsum([rr]*N, change_of_basis=p)
        self.check_disentangle(repr)
コード例 #3
0
    def representation(self) -> Representation:
        r"""
        The (combined) representations of this field type.
        They describe how the feature vectors transform under the fiber group action, that is, how the channels mix.
 
        It is the direct sum (:func:`~e2cnn.group.directsum`) of the representations in
        :attr:`e2cnn.nn.FieldType.representations`.
        
        Because a feature space can contain a very large number of feature fields, computing this representation as
        the direct sum of many small representations can be expensive.
        Hence, this representation is only built the first time it is explicitly used, in order to avoid unnecessary
        overhead when not needed.
        
        Returns:
            the :class:`~e2cnn.group.Representation` describing the whole feature space
            
        """
        if self._representation is None:
            uniques_fields_names = sorted(
                [r.name for r in self._unique_representations])
            self._representation = directsum(
                self.representations,
                name=
                f"FiberRepresentation:[{self.size}], [{uniques_fields_names}]")

        return self._representation
コード例 #4
0
 def test_regular_dihedral(self):
     g = DihedralGroup(10)
     rr = g.regular_representation
     N = 4
     size = rr.size * N
     
     p = np.eye(size, size)
     p = p[:, np.random.permutation(size)]
     repr = directsum([rr]*N, change_of_basis=p)
     self.check_disentangle(repr)
コード例 #5
0
ファイル: test_disentangle.py プロジェクト: wonjongg/e2cnn
    def test_mix_so2(self):
        space = Rot2dOnR2(-1, maximum_frequency=4)

        g = space.fibergroup
        rr = directsum(list(g.representations.values()))
        
        N = 3
        size = rr.size * N
        
        bcob = ortho_group.rvs(dim=size//5)
        bsize = bcob.shape[0]
        p = np.eye(size, size)
        
        for i in range(size//bsize):
            p[i*bsize:(i+1)*bsize, i*bsize:(i+1)*bsize] = bcob
        p = p[:, np.random.permutation(size)]
        repr = directsum([rr] * N, change_of_basis=p)

        cls = FieldType(space, [repr] * 8)
        el = DisentangleModule(cls)
        el.check_equivariance()
コード例 #6
0
def get_pre_cov_rep(G_act, dim_cov_est):
    '''
        G_act - instance of e2cnn.gspaces.r2.rot2d_on_r2.Rot2dOnR2 - underlying group
        dim_cov_est - int - either 1,2,3 or 4  - gives dimension and also the type of the covariance converter
    '''
    if dim_cov_est == 1:
        return (G_act.trivial_repr)
    elif dim_cov_est == 2:
        return (group.directsum(2 * [G_act.trivial_repr]))
    elif dim_cov_est == 3:
        return (get_eig_val_cov_conv_rep(G_act))
    elif dim_cov_est == 4:
        if isinstance(G_act, gspaces.FlipRot2dOnR2):
            vec_rep = G_act.irrep(1, 1)
        elif isinstance(G_act, gspaces.Rot2dOnR2):
            vec_rep = G_act.irrep(1)
        else:
            sys.exit('Error: unknown group.')
        return (group.directsum(2 * [vec_rep]))
    else:
        sys.exit(
            'Error when loading pre covariance representation: dim_cov_est can only be 1,2,3 or 4'
        )
コード例 #7
0
ファイル: test_disentangle.py プロジェクト: wonjongg/e2cnn
    def test_regular_dihedral(self):
        space = FlipRot2dOnR2(5)

        g = space.fibergroup
        rr = g.regular_representation
        N = 4
        size = rr.size * N
        
        p = np.eye(size, size)
        p = p[:, np.random.permutation(size)]
        repr = directsum([rr] * N, change_of_basis=p)

        cls = FieldType(space, [repr] * 8)
        el = DisentangleModule(cls)
        el.check_equivariance()
コード例 #8
0
    def check_disentangle(self, repr: Representation):
    
        group = repr.group
        
        cob, reprs = disentangle(repr)
        
        self.assertEqual(repr.size, sum([r.size for r in reprs]))
        
        ds = directsum(reprs, name="directsum")

        for e in group.testing_elements():
            repr_a = repr(e)
            repr_b = cob.T @ ds(e) @ cob

            np.set_printoptions(precision=2, threshold=2 * repr_a.size**2, suppress=True, linewidth=10*repr_a.size + 3)
            self.assertTrue(np.allclose(repr_a, repr_b), msg=f"{e}:\n{repr_a}\ndifferent from\n {repr_b}\n")
コード例 #9
0
    def check_induction_so2_o2(self, group, subgroup_id, repr):

        # print("#######################################################################################################")

        subgroup, parent, child = group.subgroup(subgroup_id)

        assert repr.group == subgroup

        # induced_repr = build_induced_representation(group, subgroup_id, repr)
        induced_repr = group.induced_representation(subgroup_id, repr)

        assert induced_repr.group == group

        assert np.allclose(
            induced_repr.change_of_basis @ induced_repr.change_of_basis_inv,
            np.eye(induced_repr.size))
        assert np.allclose(
            induced_repr.change_of_basis_inv @ induced_repr.change_of_basis,
            np.eye(induced_repr.size))

        restricted_repr = group.restrict_representation(
            subgroup_id, induced_repr)
        for e in subgroup.testing_elements():

            repr_a = repr(e)
            repr_b = induced_repr(parent(e))[:repr.size, :repr.size]
            repr_c = restricted_repr(e)[:repr.size, :repr.size]

            np.set_printoptions(precision=2,
                                threshold=2 * repr_a.size**2,
                                suppress=True,
                                linewidth=10 * repr_a.size + 3)
            self.assertTrue(
                np.allclose(repr_a, repr_b),
                msg=
                f"{group.name}\{subgroup.name}: {repr.name} - {e}:\n{repr_a}\ndifferent from\n {repr_b}\n"
            )

            if not np.allclose(repr_c, repr_b):
                print(e, parent(e))
                print(induced_repr.change_of_basis_inv @ induced_repr(
                    parent(e)) @ induced_repr.change_of_basis)
                print(restricted_repr.change_of_basis_inv @ restricted_repr(e)
                      @ restricted_repr.change_of_basis)
                print(induced_repr.irreps)
                print(restricted_repr.irreps)

                # print(induced_repr.change_of_basis)
                # print(restricted_repr.change_of_basis)
                print(
                    np.allclose(induced_repr.change_of_basis,
                                restricted_repr.change_of_basis))

            self.assertTrue(
                np.allclose(repr_c, repr_b),
                msg=
                f"{group.name}\{subgroup.name}: {repr.name} - {e}:\n{repr_c}\ndifferent from\n {repr_b}\n"
            )

        quotient_size = 2
        size = repr.size * quotient_size

        # the coset each element belongs to
        cosets = {}

        # map from a representative to the elements of its coset
        representatives = defaultdict(lambda: [])

        for e in group.testing_elements():
            flip, rot = e
            cosets[e] = (flip, 0.)
            representatives[(flip, 0.)].append(e)

        index = {e: i for i, e in enumerate(representatives)}

        P = directsum([group.irreps[irr] for irr in induced_repr.irreps],
                      name="irreps")

        for g in group.testing_elements():
            repr_g = np.zeros((size, size), dtype=np.float)
            for r in representatives:
                gr = group.combine(g, r)

                g_r = cosets[gr]

                i = index[r]
                j = index[g_r]

                hp = group.combine(group.inverse(g_r), gr)

                h = child(hp)
                assert h is not None, (g, r, gr, g_r, group.inverse(g_r), hp)

                repr_g[j * repr.size:(j + 1) * repr.size,
                       i * repr.size:(i + 1) * repr.size] = repr(h)

            ind_g = induced_repr(g)
            self.assertTrue(
                np.allclose(repr_g, ind_g),
                msg=
                f"{group.name}\{subgroup.name}: {repr.name} - {g}:\n{repr_g}\ndifferent from\n {ind_g}\n"
            )

            ind_g2 = induced_repr.change_of_basis @ P(
                g) @ induced_repr.change_of_basis_inv
            self.assertTrue(
                np.allclose(ind_g2, ind_g),
                msg=
                f"{group.name}\{subgroup.name}: {repr.name} - {g}:\n{ind_g2}\ndifferent from\n {ind_g}\n"
            )
コード例 #10
0
 def test_restrict_so2_cyclic_odd(self):
     dg = SO2(10)
     repr = directsum(list(dg.irreps.values()))
     sg_id = 7
     self.check_restriction(dg, sg_id, repr)
コード例 #11
0
 def test_restrict_o2_dihedral_odd(self):
     dg = O2(10)
     repr = directsum(list(dg.irreps.values()))
     sg_id = (0., 3)
     self.check_restriction(dg, sg_id, repr)
コード例 #12
0
ファイル: o2group.py プロジェクト: wonjongg/e2cnn
    def _induced_from_irrep(
        self,
        subgroup_id: Tuple[float, int],
        repr: IrreducibleRepresentation,
    ) -> Tuple[List[IrreducibleRepresentation], np.ndarray, np.ndarray]:

        if subgroup_id == (None, -1):
            # Induced representation from SO(2)
            # As the quotient set is finite, a finite dimensional representation of SO(2)
            # defines a finite dimensional induced representation of O(2)

            subgroup, parent, child = self.subgroup(subgroup_id)
            assert repr.group == subgroup

            name = f"induced[{subgroup_id}][{repr.name}]"

            frequency = repr.attributes["frequency"]

            if frequency > 0:
                multiplicities = [(self.irrep(1, frequency), 2)]
            else:
                multiplicities = [(self.irrep(0, 0), 1), (self.irrep(1, 0), 1)]

            irreps = []
            for irr, multiplicity in multiplicities:
                irreps += [irr] * multiplicity

            P = directsum(irreps, name=f"{name}_irreps")

            size = P.size

            v = np.zeros((repr.size, size), dtype=np.float)

            def build_commuting_matrix(rho, t):
                k = rho.attributes["frequency"]

                if rho.size == 1:
                    E = np.eye(1)
                    M = 2 * np.pi * np.eye(1)
                else:
                    E = np.array([[1, -1], [1, 1]])
                    if t % 2 == 0:
                        E = E.T
                    I = np.eye(4)
                    A = np.fliplr(np.eye(4)) * np.array([1, -1, -1, 1])
                    M = np.pi * (A + I)

                # compute the averaging of rho(g).T @ E @ rho(g)
                # i.e. X = 1/2pi Integral_{0, 2pi} rho(theta).T @ E @ rho(theta) d theta
                # as vec(X) = 1/2pi Integral_{0, 2pi} (rho *tensor* rho)(theta) @ vec(E) d theta
                # where M = Integral_{0, 2pi} (rho *tensor* rho)(theta) d theta
                X = M @ E.reshape(-1, 1)
                X /= 2 * np.pi

                # normalization
                X /= np.sqrt(np.sum(X @ X.T) / rho.size)

                X = X.reshape(rho.size, rho.size)

                return X

            p = 0
            for irr, m in multiplicities:
                assert irr.size >= m

                if m > 0:
                    restricted_irr = self.restrict_representation(
                        subgroup_id, irr)

                    n_repetitions = len([
                        name for name in restricted_irr.irreps
                        if name == repr.name
                    ])
                    assert repr.size * n_repetitions >= m, (
                        f"{self.name}\{subgroup.name}:{repr.name}", irr.name,
                        m, n_repetitions)

                    for shift in range(m):
                        commuting_matrix = build_commuting_matrix(
                            repr, shift // n_repetitions)
                        x = p
                        i = 0
                        for r_irrep in restricted_irr.irreps:
                            if r_irrep == repr.name:
                                if i == shift % n_repetitions:
                                    v[:, x:x + repr.size] = commuting_matrix
                                i += 1
                            x += subgroup.irreps[r_irrep].size

                        v[:, p:p + irr.
                          size] = v[:, p:p + irr.
                                    size] @ restricted_irr.change_of_basis_inv
                        v[:, p:p + irr.size] *= np.sqrt(irr.size)

                        p += irr.size

            v /= np.sqrt(size)

            change_of_basis = np.zeros((size, size))

            change_of_basis[:repr.size, :] = v @ P(self.identity)
            change_of_basis[repr.size:, :] = v @ P(self.reflection)

            change_of_basis_inv = change_of_basis.T

            return irreps, change_of_basis, change_of_basis_inv

        else:
            raise ValueError(
                f"Induction from discrete subgroups of O(2) leads to infinite dimensional induced "
                f"representations. Hence, induction from the subgroup identified "
                f"by {subgroup_id} is not allowed.")
コード例 #13
0
    def test_mix_o2(self):
        g = O2(6)
        rr = directsum(list(g.representations.values()))

        self.check_representation(rr)
        self.check_character(rr)
コード例 #14
0
    def test_mix_dihedral(self):
        g = DihedralGroup(10)
        rr = directsum(list(g.representations.values()))

        self.check_representation(rr)
        self.check_character(rr)
コード例 #15
0
 def test_mix_cyclic(self):
     g = CyclicGroup(15)
     rr = directsum(list(g.representations.values()))
     
     self.check_representation(rr)
     self.check_character(rr)
コード例 #16
0
 def test_restrict_o2_dihedral_even(self):
     dg = O2(10)
     repr = directsum(list(dg.irreps.values()))
     sg_id = (0., 6)
     self.check_disentangle(dg.restrict_representation(sg_id, repr))
コード例 #17
0
 def test_restrict_o2_so2(self):
     dg = O2(10)
     repr = directsum(list(dg.irreps.values()))
     sg_id = (None, -1)
     self.check_disentangle(dg.restrict_representation(sg_id, repr))
コード例 #18
0
 def test_restrict_o2_cyclic_even(self):
     dg = O2(10)
     repr = directsum(list(dg.irreps.values()))
     sg_id = (None, 4)
     self.check_restriction(dg, sg_id, repr)
コード例 #19
0
 def test_restrict_so2_cyclic_odd(self):
     dg = SO2(10)
     repr = directsum(list(dg.irreps.values()))
     sg_id = 7
     self.check_disentangle(dg.restrict_representation(sg_id, repr))
コード例 #20
0
 def test_restrict_o2_o2(self):
     dg = O2(10)
     repr = directsum(list(dg.irreps.values()))
     sg_id = (1., -1)
     self.check_restriction(dg, sg_id, repr)
コード例 #21
0
    def __init__(self,
                 hidden_reps_ids,
                 kernel_sizes,
                 dim_cov_est,
                 context_rep_ids=[1],
                 N=4,
                 flip=False,
                 non_linearity=["NormReLU"],
                 max_frequency=30):
        '''
        Input:  hidden_reps_ids - list: encoding the hidden fiber representation (see give_fib_reps_from_ids)
                kernel_sizes - list of ints - sizes of kernels for convolutional layers
                dim_cov_est - dimension of covariance estimation, either 1,2,3 or 4                
                context_rep_ids - list: gives the input fiber representation (see give_fib_reps_from_ids)
                non_linearity - list of strings - gives names of non-linearity to be used
                                    Either length 1 (then same non-linearity for all)
                                    or length is the number of layers (giving a custom non-linearity for every
                                    layer)   
                N - int - gives the group order, -1 is infinite
                flip - Bool - indicates whether we have a flip in the rotation group (i.e.O(2) vs SO(2), D_N vs C_N)
                max_frequency - int - maximum irrep frequency to computed, only relevant if N=-1
        '''

        super(SteerDecoder, self).__init__()
        #Save the rotation group, if flip is true, then include all corresponding reflections:
        self.flip = flip
        self.max_frequency = max_frequency

        if self.flip:
            self.G_act = gspaces.FlipRot2dOnR2(
                N=N) if N != -1 else gspaces.FlipRot2dOnR2(
                    N=N, maximum_frequency=self.max_frequency)
            #The output fiber representation is the identity:
            self.target_rep = self.G_act.irrep(1, 1)
        else:
            self.G_act = gspaces.Rot2dOnR2(
                N=N) if N != -1 else gspaces.Rot2dOnR2(
                    N=N, maximum_frequency=self.max_frequency)
            #The output fiber representation is the identity:
            self.target_rep = self.G_act.irrep(1)

        #Save the N defining D_N or C_N (if N=-1 it is infinity):
        self.polygon_corners = N

        #Save the id's for the context representation and extract the context fiber representation:
        self.context_rep_ids = context_rep_ids
        self.context_rep = group.directsum(
            self.give_reps_from_ids(self.context_rep_ids))

        #Save the parameters:
        self.kernel_sizes = kernel_sizes
        self.n_layers = len(hidden_reps_ids) + 2
        self.hidden_reps_ids = hidden_reps_ids
        self.dim_cov_est = dim_cov_est

        #-----CREATE LIST OF NON-LINEARITIES----
        if len(non_linearity) == 1:
            self.non_linearity = (self.n_layers - 2) * non_linearity
        elif len(non_linearity) != (self.n_layers - 2):
            sys.exit(
                "List of non-linearities invalid: must have either length 1 or n_layers-2"
            )
        else:
            self.non_linearity = non_linearity
        #-----ENDE LIST OF NON-LINEARITIES----

        #-----------CREATE DECODER-----------------
        '''
        Create a list of layers based on the kernel sizes. Compute the padding such
        that the height h and width w of a tensor with shape (batch_size,n_channels,h,w) does not change
        while being passed through the decoder
        '''
        #Create list of feature types:
        feat_types = self.give_feat_types()
        self.feature_emb = feat_types[0]
        self.feature_out = feat_types[-1]
        #Create layers list and append it:
        layers_list = [
            G_CNN.R2Conv(feat_types[0],
                         feat_types[1],
                         kernel_size=kernel_sizes[0],
                         padding=(kernel_sizes[0] - 1) // 2)
        ]
        for it in range(self.n_layers - 2):
            if self.non_linearity[it] == "ReLU":
                layers_list.append(G_CNN.ReLU(feat_types[it + 1],
                                              inplace=True))
            elif self.non_linearity[it] == "NormReLU":
                layers_list.append(G_CNN.NormNonLinearity(feat_types[it + 1]))
            else:
                sys.exit("Unknown non-linearity.")
            layers_list.append(
                G_CNN.R2Conv(feat_types[it + 1],
                             feat_types[it + 2],
                             kernel_size=kernel_sizes[it],
                             padding=(kernel_sizes[it] - 1) // 2))
        #Create a steerable decoder out of the layers list:
        self.decoder = G_CNN.SequentialModule(*layers_list)
        #-----------END CREATE DECODER---------------

        #-----------CONTROL INPUTS------------------
        #Control that all kernel sizes are odd (otherwise output shape is not correct):
        if any([j % 2 - 1 for j in kernel_sizes]):
            sys.exit("All kernels need to have odd sizes")
        if len(kernel_sizes) != (self.n_layers - 1):
            sys.exit("Number of layers and number kernels do not match.")
        if len(self.non_linearity) != (self.n_layers - 2):
            sys.exit(
                "Number of layers and number of non-linearities do not match.")