## Coverage Report

#### Created: 2026-05-04 15:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/liu/actions-runner/_work/ccv/ccv/lib/nnc/cmd/gated_delta/ccv_nnc_gated_delta_cpu_ref.c

    Line
    Count
    Source
    1
    #include "ccv.h"
    2
    #include "ccv_internal.h"
    3
    #include "nnc/ccv_nnc.h"
    4
    #include "nnc/ccv_nnc_easy.h"
    5
    #include "nnc/ccv_nnc_internal.h"
    6
    #include <math.h>
    7
    #include <string.h>
    8
    9
    static int _ccv_nnc_gated_delta_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size, ccv_nnc_stream_context_t* const stream_context)
    10
    0
    {
    11
    0
      assert(input_size == 6);
    12
    0
      assert(output_size == 2);
    13
    0
      const ccv_nnc_tensor_t* const q = inputs[0];
    14
    0
      const ccv_nnc_tensor_t* const k = inputs[1];
    15
    0
      const ccv_nnc_tensor_t* const v = inputs[2];
    16
    0
      const ccv_nnc_tensor_t* const log_decay = inputs[3];
    17
    0
      const ccv_nnc_tensor_t* const beta = inputs[4];
    18
    0
      const ccv_nnc_tensor_t* const state_in = inputs[5];
    19
    0
      ccv_nnc_tensor_t* const y = outputs[0];
    20
    0
      ccv_nnc_tensor_t* const state_out = outputs[1];
    21
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(q));
    22
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(k));
    23
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(v));
    24
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(log_decay));
    25
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(beta));
    26
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(state_in));
    27
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(y));
    28
    0
      assert(CCV_IS_TENSOR_CONTIGUOUS(state_out));
    29
    0
      assert(q->info.datatype == CCV_32F);
    30
    0
      assert(k->info.datatype == CCV_32F);
    31
    0
      assert(v->info.datatype == CCV_32F);
    32
    0
      assert(log_decay->info.datatype == CCV_32F);
    33
    0
      assert(beta->info.datatype == CCV_32F);
    34
    0
      assert(state_in->info.datatype == CCV_32F);
    35
    0
      assert(y->info.datatype == CCV_32F);
    36
    0
      assert(state_out->info.datatype == CCV_32F);
    37
    0
      const int q_nd = ccv_nnc_tensor_nd(q->info.dim);
    38
    0
      const int k_nd = ccv_nnc_tensor_nd(k->info.dim);
    39
    0
      const int v_nd = ccv_nnc_tensor_nd(v->info.dim);
    40
    0
      const int log_decay_nd = ccv_nnc_tensor_nd(log_decay->info.dim);
    41
    0
      const int beta_nd = ccv_nnc_tensor_nd(beta->info.dim);
    42
    0
      const int state_in_nd = ccv_nnc_tensor_nd(state_in->info.dim);
    43
    0
      const int y_nd = ccv_nnc_tensor_nd(y->info.dim);
    44
    0
      const int state_out_nd = ccv_nnc_tensor_nd(state_out->info.dim);
    45
    0
      assert(q_nd == 4);
    46
    0
      assert(k_nd == 4);
    47
    0
      assert(v_nd == 4);
    48
    0
      assert(log_decay_nd == 3);
    49
    0
      assert(beta_nd == 3);
    50
    0
      assert(state_in_nd == 4);
    51
    0
      assert(y_nd == 4);
    52
    0
      assert(state_out_nd == 4);
    53
    0
      const int B = q->info.dim[0];
    54
    0
      const int T = q->info.dim[1];
    55
    0
      const int Hk = q->info.dim[2];
    56
    0
      const int Dk = q->info.dim[3];
    57
    0
      const int Hv = v->info.dim[2];
    58
    0
      const int Dv = v->info.dim[3];
    59
    0
      assert(B > 0);
    60
    0
      assert(T > 0);
    61
    0
      assert(Hk > 0);
    62
    0
      assert(Dk > 0);
    63
    0
      assert(Hv > 0);
    64
    0
      assert(Dv > 0);
    65
    0
      assert(k->info.dim[0] == B);
    66
    0
      assert(k->info.dim[1] == T);
    67
    0
      assert(k->info.dim[2] == Hk);
    68
    0
      assert(k->info.dim[3] == Dk);
    69
    0
      assert(v->info.dim[0] == B);
    70
    0
      assert(v->info.dim[1] == T);
    71
    0
      assert(log_decay->info.dim[0] == B);
    72
    0
      assert(log_decay->info.dim[1] == T);
    73
    0
      assert(log_decay->info.dim[2] == Hv);
    74
    0
      assert(beta->info.dim[0] == B);
    75
    0
      assert(beta->info.dim[1] == T);
    76
    0
      assert(beta->info.dim[2] == Hv);
    77
    0
      assert(state_in->info.dim[0] == B);
    78
    0
      assert(state_in->info.dim[1] == Hv);
    79
    0
      assert(state_in->info.dim[2] == Dv);
    80
    0
      assert(state_in->info.dim[3] == Dk);
    81
    0
      assert(y->info.dim[0] == B);
    82
    0
      assert(y->info.dim[1] == T);
    83
    0
      assert(y->info.dim[2] == Hv);
    84
    0
      assert(y->info.dim[3] == Dv);
    85
    0
      assert(state_out->info.dim[0] == B);
    86
    0
      assert(state_out->info.dim[1] == Hv);
    87
    0
      assert(state_out->info.dim[2] == Dv);
    88
    0
      assert(state_out->info.dim[3] == Dk);
    89
    0
      assert(Hv % Hk == 0);
    90
    0
      const int log_decay_input = cmd.info.gated_delta.log_decay;
    91
    0
      const int hv_per_hk = Hv / Hk;
    92
    0
      const float* const qp = q->data.f32;
    93
    0
      const float* const kp = k->data.f32;
    94
    0
      const float* const vp = v->data.f32;
    95
    0
      const float* const gp = log_decay->data.f32;
    96
    0
      const float* const betap = beta->data.f32;
    97
    0
      const float* const state_inp = state_in->data.f32;
    98
    0
      float* const yp = y->data.f32;
    99
    0
      float* const state_outp = state_out->data.f32;
    100
    0
      int b, hv, dv, t, dk;
    101
    0
      for (b = 0; b < B; b++)
    102
    0
        for (hv = 0; hv < Hv; hv++)
    103
    0
        {
    104
    0
          const int hk = hv / hv_per_hk;
    105
    0
          for (dv = 0; dv < Dv; dv++)
    106
    0
          {
    107
    0
            const size_t state_offset = (((size_t)b * Hv + hv) * Dv + dv) * Dk;
    108
    0
            if (state_inp != state_outp)
    109
    0
              memcpy(state_outp + state_offset, state_inp + state_offset, sizeof(float) * Dk);
    110
    0
            float* const state_row = state_outp + state_offset;
    111
    0
            for (t = 0; t < T; t++)
    112
    0
            {
    113
    0
              const size_t qk_offset = (((size_t)b * T + t) * Hk + hk) * Dk;
    114
    0
              const float* const q_row = qp + qk_offset;
    115
    0
              const float* const k_row = kp + qk_offset;
    116
    0
              const size_t gate_offset = ((size_t)b * T + t) * Hv + hv;
    117
    0
              const float decay = log_decay_input ? expf(gp[gate_offset]) : gp[gate_offset];
    118
    0
              float memory = 0;
    119
    0
              for (dk = 0; dk < Dk; dk++)
    120
    0
              {
    121
    0
                const float decayed = state_row[dk] * decay;
    122
    0
                state_row[dk] = decayed;
    123
    0
                memory += decayed * k_row[dk];
    124
    0
              }
    125
    0
              const size_t v_offset = (((size_t)b * T + t) * Hv + hv) * Dv + dv;
    126
    0
              const float delta = (vp[v_offset] - memory) * betap[gate_offset];
    127
    0
              float out = 0;
    128
    0
              for (dk = 0; dk < Dk; dk++)
    129
    0
              {
    130
    0
                const float next = state_row[dk] + delta * k_row[dk];
    131
    0
                state_row[dk] = next;
    132
    0
                out += next * q_row[dk];
    133
    0
              }
    134
    0
              yp[v_offset] = out;
    135
    0
            }
    136
    0
          }
    137
    0
        }
    138
    0
      return CCV_NNC_EXEC_SUCCESS;
    139
    0
    }
    140
    141
    REGISTER_COMMAND_BACKEND(CCV_NNC_GATED_DELTA_FORWARD, CCV_NNC_BACKEND_CPU_REF)(ccv_nnc_cmd_backend_registry_t* const registry)
    142
    1
    {
    143
    1
      registry->tensor_formats = CCV_TENSOR_FORMAT_NHWC | CCV_TENSOR_FORMAT_NCHW | CCV_TENSOR_FORMAT_CHWN;
    144
    1
      registry->tensor_datatypes = CCV_32F;
    145
    1
      registry->tensor_memory = CCV_TENSOR_CPU_MEMORY;
    146
    1
      registry->algorithms = 1;
    147
    1
      registry->exec = _ccv_nnc_gated_delta_forw;
    148
    1
    }