GLU
=================

Gated Linear Unit（门控线性单元）算子。该算子将输入张量在指定维度（``split_dim``）上分割成两个相等的部分（A和B），然后对第二部分（B）应用Sigmoid激活函数，并将其与第一部分（A）逐元素相乘。

.. math::

   \text{out} = A \otimes \sigma(B)

其中，A和B是输入张量沿 ``split_dim`` 维度分割后的两个子张量，:math:`\sigma` 是Sigmoid函数，:math:`\otimes` 表示逐元素乘法。

输入：
    - **in_data** - 输入张量的数据地址。
    - **split_data** - 一个指针数组，用于存放分割后的子张量地址（作为临时缓冲区）。
    - **out_data** - 输出张量的数据地址。
    - **ndim** - 输入张量的维度数量。
    - **split_dim** - 执行分割操作的目标维度轴。
    - **input_shape** - 指向一个整数数组的指针，该数组描述了输入张量的形状。
    - **num_split** - 分割的数量，对于GLU操作，此值应为2。
    - **split_sizes** - 指向一个整数数组的指针，该数组描述了每个子张量在 ``split_dim`` 维度上的大小。
    - **strides** - 指向一个整数数组的指针，用于存放为张量索引预先计算好的步长。
    - **len** - 输出张量中的元素总数。
    - **core_mask** - 核掩码 (仅共享存储版本需要)。

输出：
   - **out_data** - 存储GLU计算结果的张量。其形状与输入张量相同，但在 ``split_dim`` 维度上的大小减半。

支持平台：
    ``FT78NE``  
    ``MT7004``

.. note::
     - FT78NE支持fp32和int8类型。
     - MT7004支持fp16和fp32类型。
      
**共享存储版本:**

.. c:function:: void i8_glu_s(int8_t* in_data, int8_t** split_data, int8_t* out_data, int ndim, int split_dim, int* input_shape, int num_split, int* split_sizes, int* strides, int len, int core_mask)
.. c:function:: void hp_glu_s(half* in_data, half** split_data, half* out_data, int ndim, int split_dim, int* input_shape, int num_split, int* split_sizes, int* strides, int len, int core_mask)
.. c:function:: void fp_glu_s(float* in_data, float** split_data, float* out_data, int ndim, int split_dim, int* input_shape, int num_split, int* split_sizes, int* strides, int len, int core_mask)

**C调用示例：**

.. code-block:: c
   :linenos:
   :emphasize-lines: 21

   // 7004平台, fp32示例
   #include <stdio.h>
   #include "glu.h" 

   int main(int argc, char* argv[]) {
       float *in_data = (float *)0xA0000000;      // input在DDR空间
       float *out_data = (float *)0xC0000000;     // output在DDR空间
       float *split_data_buf[2];                  // 临时缓冲区指针
       // ... (需要为split_data_buf分配内存)

       // 假设张量属性已定义
       int ndim = 2;
       int split_dim = 1;
       int input_shape[] = {2, 4};
       int num_split = 2;
       int split_sizes[] = {2, 2};
       int len = 4;
       int strides[2]; // 需要预先计算
       int core_mask = 0xff;

       fp_glu_s(in_data, split_data_buf, out_data, ndim, split_dim, input_shape, num_split, split_sizes, strides, len, core_mask);
       return 0;
   }


**私有存储版本:**

.. c:function:: void i8_glu_p(int8_t* in_data, int8_t** split_data, int8_t* out_data, int ndim, int split_dim, int* input_shape, int num_split, int* split_sizes, int* strides, int len)
.. c:function:: void hp_glu_p(half* in_data, half** split_data, half* out_data, int ndim, int split_dim, int* input_shape, int num_split, int* split_sizes, int* strides, int len)
.. c:function:: void fp_glu_p(float* in_data, float** split_data, float* out_data, int ndim, int split_dim, int* input_shape, int num_split, int* split_sizes, int* strides, int len)
    
**C调用示例：**

.. code-block:: c
   :linenos:
   :emphasize-lines: 20

   // 7004平台, fp32示例
   #include <stdio.h>
   #include "glu.h" 

   int main(int argc, char* argv[]) {
       float *in_data = (float *)0x10000000;     // input在L2空间
       float *out_data = (float *)0x10001000;    // output在L2空间
       float *split_data_buf[2];                 // 临时缓冲区指针
       // ... (需要为split_data_buf分配内存)

       // 假设张量属性已定义
       int ndim = 2;
       int split_dim = 1;
       int input_shape[] = {2, 4};
       int num_split = 2;
       int split_sizes[] = {2, 2};
       int len = 4;
       int strides[2]; // 需要预先计算

       fp_glu_p(in_data, split_data_buf, out_data, ndim, split_dim, input_shape, num_split, split_sizes, strides, len);
       return 0;
   }
