Exemplo n.º 1
0
    def test_induce_rr_dihedral_even_flips(self):
        dg = dihedral_group(10)

        sg_id = (0, 1)
        sg, _, _ = dg.subgroup(sg_id)
        repr = sg.regular_representation
        self.check_induction(dg, sg_id, repr)
Exemplo n.º 2
0
 def test_induce_irreps_dihedral_odd_flips(self):
     dg = dihedral_group(11)
     for axis in range(11):
         sg_id = (axis, 1)
         sg, _, _ = dg.subgroup(sg_id)
         for name, irrep in sg.irreps.items():
             self.check_induction(dg, sg_id, irrep)
    def test_quotient_dihedral(self):
        N = 7
        dg = dihedral_group(N)

        sg_id = (None, 1)
        sg, _, _ = dg.subgroup(sg_id)
        self.check_induction(dg, sg_id, sg.trivial_representation)
Exemplo n.º 4
0
    def test_induce_irreps_dihedral_even_dihedral_even(self):
        dg = dihedral_group(12)
        for axis in range(2):
            sg_id = (axis, 6)

            sg, _, _ = dg.subgroup(sg_id)
            for name, irrep in sg.irreps.items():
                self.check_induction(dg, sg_id, irrep)
Exemplo n.º 5
0
 def test_quotient_dihedral_odd(self):
     N = 21
     dg = dihedral_group(N)
     for n in range(1, int(round(np.sqrt(N))) + 1):
         if N % n == 0:
             for f in range(N // n):
                 sg_id = (f, n)
                 sg, _, _ = dg.subgroup(sg_id)
                 self.check_induction(dg, sg_id, sg.trivial_representation)
             sg_id = (None, n)
             sg, _, _ = dg.subgroup(sg_id)
             self.check_induction(dg, sg_id, sg.trivial_representation)
Exemplo n.º 6
0
    def __init__(self, N: int = None, maximum_frequency: int = None, axis: float = np.pi / 2, fibergroup: Group = None):
        r"""
        
        Describes reflectional and rotational symmetries of the plane :math:`\R^2`.
        
        Reflections are applied with respect to the line through the origin with an angle ``axis`` degrees with respect
        to the *X*-axis.
        
        If ``N > 1``, the class models reflections and *discrete* rotations by angles multiple of :math:`\frac{2\pi}{N}`
        (:class:`~e2cnn.group.DihedralGroup`).
        Otherwise, if ``N=-1``, the class models reflections and *continuous* planar rotations
        (:class:`~e2cnn.group.O2`).
        In that case the parameter ``maximum_frequency`` is required to specify the maximum frequency of the irreps of
        :class:`~e2cnn.group.O2` (see its documentation for more details)
        
        .. note ::
            
            All axes obtained from the axis defined by ``axis`` with a rotation in the symmetry group are equivalent.
            For instance, if ``N = 4``, an axis :math:`\beta` is equivalent to the axis :math:`\beta + \pi/2`.
            It follows that for ``N = -1``, i.e. in case the symmetry group contains all continuous rotations, any
            reflection axis is theoretically equivalent.
            In practice, though, a basis for equivariant convolutional filter sampled on a grid is affected by the
            specific choice of the axis. In general, choosing an axis aligned with the grid (an horizontal or a
            vertical axis, i.e. :math:`0` or :math:`\pi/2`) is suggested.
        
        Args:
            N (int): number of discrete rotations (integer greater than 1) or -1 for continuous rotations
            maximum_frequency (int): maximum frequency of :class:`~e2cnn.group.O2` 's irreps if ``N = -1``
            axis (float, optional): the slope of the axis of the flip (in radians)
            fibergroup (Group, optional): use an already existing instance of the symmetry group.
                    In that case only the parameter ``axis`` should be used.
        
        Attributes:
            ~.axis (float): Angle with respect to the horizontal axis which defines the reflection axis.
            
        """

        assert N is not None or fibergroup is not None, "Error! Either use the parameter `N` or the parameter `group`!"

        if fibergroup is not None:
            assert isinstance(fibergroup, DihedralGroup) or isinstance(fibergroup, O2)
            assert maximum_frequency is None, "Maximum Frequency can't be set when the group is already provided in input"
            N = fibergroup.rotation_order
    
        assert isinstance(N, int)

        self.axis = axis
        
        if N > 1:
            assert maximum_frequency is None, "Maximum Frequency can't be set for finite cyclic groups"
            name = 'Flip_{}-Rotations(f={:.5f})'.format(N, self.axis)
        elif N == -1:
            name = 'Flip_Continuous-Rotations(f={:.5f})'.format(self.axis)
            # self.axis = np.pi/2
        else:
            raise ValueError(f'Error! "N" has to be an integer greater than 1 or -1, but got {N}')
    
        if fibergroup is None:
            if N > 1:
                fibergroup = dihedral_group(N)
            elif N == -1:
                fibergroup = o2_group(maximum_frequency)
    
        super(FlipRot2dOnR2, self).__init__(fibergroup, name)
Exemplo n.º 7
0
 def test_induce_irreps_dihedral_odd_cyclic_odd(self):
     dg = dihedral_group(9)
     sg_id = (None, 3)
     sg, _, _ = dg.subgroup(sg_id)
     for name, irrep in sg.irreps.items():
         self.check_induction(dg, sg_id, irrep)
Exemplo n.º 8
0
 def test_induce_rr_dihedral_odd_cyclic_odd(self):
     dg = dihedral_group(9)
     sg_id = (None, 3)
     sg, _, _ = dg.subgroup(sg_id)
     repr = sg.regular_representation
     self.check_induction(dg, sg_id, repr)
Exemplo n.º 9
0
    def __init__(
        self,
        group: Union[Group, int],
        in_irrep: Union[str, IrreducibleRepresentation, Tuple[int]],
        out_irrep: Union[str, IrreducibleRepresentation, Tuple[int, int]],
        axis: float,
        max_frequency: int = None,
        max_offset: int = None,
    ):

        if isinstance(group, int):
            group = dihedral_group(group)

        assert isinstance(group, DihedralGroup)

        assert (max_frequency is not None or max_offset is not None), \
            'Error! Either the maximum frequency or the maximum offset for the frequencies must be set'

        self.max_frequency = max_frequency
        self.max_offset = max_offset

        assert max_frequency is None or (isinstance(max_frequency, int)
                                         and max_frequency >= 0)
        assert max_offset is None or (isinstance(max_offset, int)
                                      and max_offset >= 0)

        assert isinstance(axis, float)
        self.axis = axis

        if isinstance(in_irrep, tuple):
            in_irrep = group.irrep(in_irrep[0], in_irrep[1])
        elif isinstance(in_irrep, str):
            in_irrep = group.irreps[in_irrep]
        elif not isinstance(in_irrep, IrreducibleRepresentation):
            raise ValueError(
                f"'in_irrep' should be a non-negative integer, a string or an instance"
                f" of IrreducibleRepresentation but {in_irrep} found")

        if isinstance(out_irrep, tuple):
            out_irrep = group.irrep(out_irrep[0], out_irrep[1])
        elif isinstance(out_irrep, str):
            out_irrep = group.irreps[out_irrep]
        elif not isinstance(out_irrep, IrreducibleRepresentation):
            raise ValueError(
                f"'out_irrep' should be a non-negative integer, a string or an instance"
                f" of IrreducibleRepresentation but {in_irrep} found")

        self.N = group.rotation_order

        self.m = out_irrep.attributes['frequency']
        self.n = in_irrep.attributes['frequency']

        self.fi = in_irrep.attributes['flip_frequency']
        self.fo = out_irrep.attributes['flip_frequency']

        self.ts = []

        if in_irrep.size == 2 and out_irrep.size == 2:
            assert (self.m > 0 and self.n > 0 and self.fi == 1
                    and self.fo == 1)
            # m, n > 0
            mus = []
            ss = []

            self.gamma = 0.
            for s in [0, 1]:
                k = self.m - self.n * (-1)**s

                # for each available frequency offset, build the corresponding basis vector
                for t in offset_iterator(k, self.N, self.max_offset,
                                         self.max_frequency):

                    # the current shifted frequency
                    mu = k + t * self.N

                    if self.max_offset is not None:
                        assert (math.fabs(t) <=
                                self.max_offset), (t, self.max_offset)

                    if self.max_frequency is not None:
                        assert (math.fabs(mu) <= self.max_frequency), (
                            k, t, mu, self.max_frequency)

                    mus.append(mu)
                    ss.append(s)
                    self.ts.append(t)

            self.mu = np.array(mus).reshape(-1, 1)
            self.s = np.array(ss).reshape(-1, 1)

        elif in_irrep.size == 2 and out_irrep.size == 1:
            assert ((self.m == 0 or
                     (self.m == self.N // 2 and self.N % 2 == 0))
                    and (self.fi == 1))
            # n > 0, m = 0 or N/2

            self.gamma = self.fo * np.pi / 2
            mus = []

            k = self.n + self.m

            # for each available frequency offset, build the corresponding basis vector
            for t in offset_iterator(k, self.N, self.max_offset,
                                     self.max_frequency):

                # the current shifted frequency
                mu = k + t * self.N

                if self.max_offset is not None:
                    assert (math.fabs(t) <= self.max_offset), (t,
                                                               self.max_offset)

                if self.max_frequency is not None:
                    assert (math.fabs(mu) <=
                            self.max_frequency), (k, t, mu, self.max_frequency)

                mus.append(mu)
                self.ts.append(t)

            self.mu = np.array(mus).reshape(-1, 1)

        elif in_irrep.size == 1 and out_irrep.size == 2:
            assert ((self.n == 0 or
                     (self.n == self.N // 2 and self.N % 2 == 0))
                    and self.fo == 1)
            # m > 0, n = 0 or N/2

            self.gamma = self.fi * np.pi / 2
            mus = []

            k = self.n + self.m

            # for each available frequency offset, build the corresponding basis vector
            for t in offset_iterator(k, self.N, self.max_offset,
                                     self.max_frequency):

                # the current shifted frequency
                mu = k + t * self.N

                if self.max_offset is not None:
                    assert (math.fabs(t) <= self.max_offset), (t,
                                                               self.max_offset)

                if self.max_frequency is not None:
                    assert (math.fabs(mu) <=
                            self.max_frequency), (k, t, mu, self.max_frequency)

                mus.append(mu)
                self.ts.append(t)

            self.mu = np.array(mus).reshape(-1, 1)

        elif in_irrep.size == 1 and out_irrep.size == 1:
            assert (self.n == 0 or (self.n == self.N // 2 and self.N % 2 == 0))
            assert (self.m == 0 or (self.m == self.N // 2 and self.N % 2 == 0))

            self.gamma = ((self.fi + self.fo) % 2) * np.pi / 2
            mus = []

            k = self.m - self.n

            # for each available frequency offset, build the corresponding basis vector
            for t in offset_iterator(k,
                                     self.N,
                                     self.max_offset,
                                     self.max_frequency,
                                     non_negative=True):

                # the current shifted frequency
                mu = k + t * self.N

                if self.max_offset is not None:
                    assert (math.fabs(t) <= self.max_offset), (t,
                                                               self.max_offset)

                if self.max_frequency is not None:
                    assert (math.fabs(mu) <=
                            self.max_frequency), (k, t, mu, self.max_frequency)

                if mu > 0 or self.gamma == 0.:
                    # don't add sin(0*theta) as a basis since it is zero everywhere
                    mus.append(mu)
                    self.ts.append(t)

            self.mu = np.array(mus).reshape(-1, 1)

        self._non_zero_frequencies = self.mu != 0
        self._has_non_zero_frequencies = np.any(self._non_zero_frequencies)

        dim = self.mu.shape[0]
        super(R2FlipsDiscreteRotationsSolution,
              self).__init__(group, in_irrep, out_irrep, dim)