/// <summary>
        /// Reshape the bottom (input) and top (output) blobs.
        /// </summary>
        /// <param name="colBottom">Specifies the collection of bottom (input) Blobs.</param>
        /// <param name="colTop">Specifies the collection of top (output) Blobs.</param>
        public override void Reshape(BlobCollection <T> colBottom, BlobCollection <T> colTop)
        {
            T[]        rgOldSteps = new T[m_nNumAxes];
            T[]        rgNewSteps = new T[m_nNumAxes];
            T[]        rgOrder1   = m_blobPermuteOrder.mutable_cpu_data;
            List <int> rgOrder    = new List <int>();

            for (int i = 0; i < rgOrder1.Length; i++)
            {
                if (i < m_nNumAxes)
                {
                    if (i == m_nNumAxes - 1)
                    {
                        rgOldSteps[i] = m_tOne;
                    }
                    else
                    {
                        rgOldSteps[i] = Utility.ConvertVal <T>(colBottom[0].count(i + 1));
                    }
                }

                rgOrder.Add((int)Utility.ConvertVal <T>(rgOrder1[i]));
            }

            m_blobOldSteps.mutable_cpu_data = rgOldSteps;
            List <int> rgTopShape = PermuteParameter.Reshape(rgOrder, colBottom[0].shape(), colBottom[0].num_axes);

            colTop[0].Reshape(rgTopShape);

            for (int i = 0; i < m_nNumAxes; i++)
            {
                if (i == m_nNumAxes - 1)
                {
                    rgNewSteps[i] = m_tOne;
                }
                else
                {
                    rgNewSteps[i] = Utility.ConvertVal <T>(colTop[0].count(i + 1));
                }
            }

            m_blobNewSteps.mutable_cpu_data = rgNewSteps;
        }
        /// <summary>
        /// Setup the layer.
        /// </summary>
        /// <param name="colBottom">Specifies the collection of bottom (input) Blobs.</param>
        /// <param name="colTop">Specifies the collection of top (output) Blobs.</param>
        public override void LayerSetUp(BlobCollection <T> colBottom, BlobCollection <T> colTop)
        {
            m_log.CHECK_EQ(colBottom.Count, 1, "There should only be one botom blob.");
            PermuteParameter permute_param = layer_param.permute_param;

            m_nNumAxes = colBottom[0].num_axes;

            // Push the specified new orders
            List <int> rgOrders = new List <int>();

            foreach (int nOrder in permute_param.order)
            {
                m_log.CHECK_LT(nOrder, m_nNumAxes, "The order should be less than the input dimension '" + m_nNumAxes.ToString() + "'!");

                if (rgOrders.Contains(nOrder))
                {
                    m_log.FAIL("The order '" + nOrder.ToString() + "' is a duplicate order!");
                }

                rgOrders.Add(nOrder);
            }

            // Push the rest of the orders and save the orginal step sizes for each axis.
            for (int i = 0; i < m_nNumAxes; i++)
            {
                if (!rgOrders.Contains(i))
                {
                    rgOrders.Add(i);
                }
            }

            m_log.CHECK_EQ(rgOrders.Count, m_nNumAxes, "The order count should be the same as the input dimension of '" + m_nNumAxes.ToString() + "'!");

            // Check if we need to reorder the data or keep it.
            m_bNeedPermute = false;

            for (int i = 0; i < m_nNumAxes; i++)
            {
                if (rgOrders[i] != i)
                {
                    // As long as there is one order which is different from the natural order
                    // of the data, we need to permute.  Otherwise, we share the data and diff.
                    m_bNeedPermute = true;
                    break;
                }
            }

            List <int> rgTopShape = Utility.Create <int>(m_nNumAxes, 1);

            m_blobPermuteOrder.Reshape(m_nNumAxes, 1, 1, 1);
            m_blobOldSteps.ReshapeLike(m_blobPermuteOrder);
            m_blobNewSteps.ReshapeLike(m_blobPermuteOrder);

            T[] rgOrder1 = new T[m_nNumAxes];
            for (int i = 0; i < m_nNumAxes; i++)
            {
                int nOrder = rgOrders[i];
                rgOrder1[i] = Utility.ConvertVal <T>(nOrder);
                int nShape = colBottom[0].shape(nOrder);
                rgTopShape[i] = nShape;
            }

            m_blobPermuteOrder.mutable_cpu_data = rgOrder1;
            colTop[0].Reshape(rgTopShape);
        }