encoder() ======================================== .. py:function:: grassmanntn.param.encoder(index) The encoder-switching function---convert the canonical index to parity-preserving index and vice versa. **Parameters:** - **index:** ``int`` The composite index :math:`I` in the canonical or parity-preserving encoder. **Returns:** - **out:** ``int`` The composite index in a different encoder. Description +++++++++++ The composite index can be under two encodings: `canonical` and `parity-preserving`. .. math:: I_\text{canonical}(i_1,\cdots,i_n) = \sum_{a=1}^n 2^{a-1}i_a, .. math:: I_\text{parity-preserving}(i_1,\cdots,i_n) = \left\{ \begin{array}{ll} \sum_{a=1}^n 2^{a-1}i_a & ; i_2+\cdots+i_n\;\text{even},\\ 1-i_1+\sum_{a=2}^n 2^{a-1}i_a & ; i_2+\cdots+i_n\;\text{odd}. \end{array} \right. Please see the `paper `__ for more details. This function is self-inverse (see the proof below), so it will operate with the assumption that the input is in the canonical encoder, without loss of generality. The function first convert :math:`I` into the bits representation, then the parity-preserving encoding is applied. Proof of the self-inverse ------------------------- The encoder-switching function :math:`\varepsilon(I)`, where :math:`I` is in the canonical encoder, can be written in a compact form as .. math:: \varepsilon(I) = \left\{ \begin{array}{ll} I & ; p(I)-i_1\;\text{even},\\ 1-2i_1+I & ; p(I)-i_1\;\text{odd}. \end{array} \right. Since :math:`i_1=I\;\text{mod}\;2`, we have .. math:: \varepsilon(I) = \left\{ \begin{array}{ll} I & ; p(I)-I\;\text{even},\\ 1-2(I\;\text{mod}\;2)+I & ; p(I)-I\;\text{odd}. \end{array} \right. We next consider applying :math:`\varepsilon` twice on an integer :math:`I`. There are three possible cases: - Both :math:`I` and :math:`p(I)` are of the same parity Then :math:`p(I)-I` is even, which means that :math:`\varepsilon(I)=I` and thus :math:`\varepsilon(\varepsilon(I))=I`. - :math:`I` is odd and :math:`p(I)` is even Then :math:`\varepsilon(I)=I-1` is even. Note that when :math:`I` is odd, then the first bit must be 1, meaning that every bits of :math:`I-1` is the same as :math:`I` except for the first one which is 0. It also means that if :math:`p(I)` is even, then :math:`p(I-1)=p(\varepsilon(I))` must be odd because there is only one bit that are different between :math:`I` and :math:`I-1`. All of this implies that :math:`p(\varepsilon(I))-\varepsilon(I)` must be odd. It follows that .. math:: \varepsilon(\varepsilon(I)) = \varepsilon(I-1) = 1-2( (I-1)\;\text{mod}\;2 ) + (I-1) = I. - :math:`I` is even and :math:`p(I)` is odd Then :math:`\varepsilon(I)=I+1` is odd. Using the same logic about the first bit as in the previous case, we arrive at the fact that :math:`p(\varepsilon(I))-\varepsilon(I)` must be odd. It follows that .. math:: \varepsilon(\varepsilon(I)) = \varepsilon(I+1) = 1-2( (I+1)\;\text{mod}\;2 ) + (I+1) = I. In every case above, we have :math:`\varepsilon(\varepsilon(I))=I` which means that :math:`\varepsilon(I)` is self-inverse. QED