New k-tokenizer based on recursively splitting vectors
authorJean-Marc Valin <jmvalin@jmvalin.ca>
Thu, 17 Mar 2016 18:21:19 +0000 (14:21 -0400)
committerJean-Marc Valin <jmvalin@jmvalin.ca>
Sat, 2 Apr 2016 18:38:54 +0000 (14:38 -0400)
subset1:
          LOW (%)  MEDIUM (%) HIGH (%)
    PSNR -0.364142 -0.486323 -0.793959
 PSNRHVS -0.197596 -0.203733 -0.150378
    SSIM -0.413834 -0.473294 -0.761453
FASTSSIM -0.345152 -0.321699 -0.817306

ntt-short1:
          LOW (%)  MEDIUM (%) HIGH (%)
    PSNR -0.073705 0.054435 0.089627
 PSNRHVS 0.145926 0.212215 -0.005988
    SSIM -0.048457 -0.017962 -0.114289
FASTSSIM 0.253182 0.223012 -0.962983

src/laplace_decoder.c
src/laplace_encoder.c
src/pvq.c
src/pvq.h
src/pvq_decoder.c
src/pvq_decoder.h
src/pvq_encoder.c
src/pvq_encoder.h

index 3453f53..684c482 100644 (file)
@@ -34,6 +34,60 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
 #include "odintrin.h"
 #include "pvq.h"
 
+#if OD_ACCOUNTING
+# define od_decode_pvq_split(ec, adapt, sum, ctx, str) od_decode_pvq_split_(ec, adapt, sum, ctx, str)
+#else
+# define od_decode_pvq_split(ec, adapt, sum, ctx, str) od_decode_pvq_split_(ec, adapt, sum, ctx)
+#endif
+
+static int od_decode_pvq_split_(od_ec_dec *ec, od_pvq_codeword_ctx *adapt,
+ int sum, int ctx OD_ACC_STR) {
+  int shift;
+  int count;
+  int msbs;
+  count = 0;
+  if (sum == 0) return 0;
+  shift = OD_MAXI(0, OD_ILOG(sum) - 3);
+  msbs = od_decode_cdf_adapt(ec, adapt->pvq_split_cdf[7*ctx + (sum >> shift)
+   - 1], (sum >> shift) + 1, adapt->pvq_split_increment, acc_str) << shift;
+  if (shift) count = od_ec_dec_bits(ec, shift, acc_str);
+  count += msbs;
+  if (count > sum) {
+    count = sum;
+    ec->error = 1;
+  }
+  return count;
+}
+
+void od_decode_band_pvq_splits(od_ec_dec *ec, od_pvq_codeword_ctx *adapt,
+ od_coeff *y, int n, int k, int level) {
+  int mid;
+  int count_right;
+  if (n == 1) {
+    y[0] = k;
+  }
+  else if (k == 0) {
+    OD_CLEAR(y, n);
+  }
+  else if (k == 1 && n <= 16) {
+    int cdf_id;
+    int pos;
+    cdf_id = od_pvq_k1_ctx(n, level == 0);
+    OD_CLEAR(y, n);
+    pos = od_decode_cdf_adapt(ec, adapt->pvq_k1_cdf[cdf_id], n,
+     adapt->pvq_k1_increment, "pvq:k1");
+    y[pos] = 1;
+  }
+  else {
+    mid = n >> 1;
+    count_right = od_decode_pvq_split(ec, adapt, k, od_pvq_size_ctx(n),
+     "pvq:split");
+    od_decode_band_pvq_splits(ec, adapt, y, mid, k - count_right, level + 1);
+    od_decode_band_pvq_splits(ec, adapt, y + mid, n - mid, count_right,
+     level + 1);
+  }
+}
+
 /** Decodes the tail of a Laplace-distributed variable, i.e. it doesn't
  * do anything special for the zero case.
  *
index 12d7944..c8f5607 100644 (file)
@@ -35,6 +35,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
 #include "logging.h"
 #include "odintrin.h"
 
+static void od_encode_pvq_split(od_ec_enc *ec, od_pvq_codeword_ctx *adapt,
+ int count, int sum, int ctx) {
+  int shift;
+  int rest;
+  if (sum == 0) return;
+  shift = OD_MAXI(0, OD_ILOG(sum) - 3);
+  if (shift) {
+    rest = count & ((1 << shift) - 1);
+    count >>= shift;
+    sum >>= shift;
+  }
+  od_encode_cdf_adapt(ec, count, adapt->pvq_split_cdf[7*ctx + sum - 1],
+   sum + 1, adapt->pvq_split_increment);
+  if (shift) od_ec_enc_bits(ec, rest, shift);
+}
+
+void od_encode_band_pvq_splits(od_ec_enc *ec, od_pvq_codeword_ctx *adapt,
+ const int *y, int n, int k, int level) {
+  int mid;
+  int i;
+  int count_right;
+  if (n <= 1 || k == 0) return;
+  if (k == 1 && n <= 16) {
+    int cdf_id;
+    int pos;
+    cdf_id = od_pvq_k1_ctx(n, level == 0);
+    for (pos = 0; !y[pos]; pos++);
+    OD_ASSERT(pos < n);
+    od_encode_cdf_adapt(ec, pos, adapt->pvq_k1_cdf[cdf_id], n,
+     adapt->pvq_k1_increment);
+  }
+  else {
+    mid = n >> 1;
+    count_right = k;
+    for (i = 0; i < mid; i++) count_right -= abs(y[i]);
+    od_encode_pvq_split(ec, adapt, count_right, k, od_pvq_size_ctx(n));
+    od_encode_band_pvq_splits(ec, adapt, y, mid, k - count_right, level + 1);
+    od_encode_band_pvq_splits(ec, adapt, y + mid, n - mid, count_right,
+     level + 1);
+  }
+}
+
 /** Encodes the tail of a Laplace-distributed variable, i.e. it doesn't
  * do anything special for the zero case.
  *
index 0b3df6d..8efdac7 100644 (file)
--- a/src/pvq.c
+++ b/src/pvq.c
@@ -284,7 +284,8 @@ void od_adapt_pvq_ctx_reset(od_pvq_adapt_ctx *state, int is_keyframe) {
   OD_CDFS_INIT(state->pvq_gaintheta_cdf, state->pvq_gaintheta_increment >> 2);
   state->pvq_skip_dir_increment = 128;
   OD_CDFS_INIT(state->pvq_skip_dir_cdf, state->pvq_skip_dir_increment >> 2);
-
+  ctx->pvq_split_increment = 128;
+  OD_CDFS_INIT(ctx->pvq_split_cdf, ctx->pvq_split_increment >> 1);
 }
 
 /* QMs are arranged from smallest to largest blocksizes, first for
@@ -342,6 +343,30 @@ void od_init_qm(int16_t *x, int16_t *x_inv, const int *qm) {
   }
 }
 
+/* Maps each possible size (n) in the split k-tokenizer to a different value.
+   Possible values of n are:
+   2, 3, 4, 7, 8, 14, 15, 16, 31, 32, 63, 64, 127, 128
+   Since we don't care about the order (even in the bit-stream) the simplest
+   ordering (implemented here) is:
+   14, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 */
+int od_pvq_size_ctx(int n) {
+  int logn;
+  int odd;
+  logn = OD_ILOG(n - 1);
+  odd = n & 1;
+  return 2*logn - 1 - odd - 7*(n == 14);
+}
+
+/* Maps a length n to a context for the (k=1, n<=16) coder, with a special
+   case when n is the original length (orig_length=1) of the vector (i.e. we
+   haven't split it yet). For orig_length=0, we use the same mapping as
+   od_pvq_size_ctx() up to n=16. When orig_length=1, we map lengths
+   7, 8, 14, 15 to contexts 8 to 11. */
+int od_pvq_k1_ctx(int n, int orig_length) {
+  if (orig_length) return 8 + 2*(n > 8) + (n & 1);
+  else return od_pvq_size_ctx(n);
+}
+
 /* Indexing for the packed quantization matrices. */
 int od_qm_get_index(int bs, int band) {
   /* The -band/3 term is due to the fact that we force corresponding horizontal
index 6ea5de8..676730b 100644 (file)
--- a/src/pvq.h
+++ b/src/pvq.h
@@ -116,7 +116,9 @@ struct od_pvq_codeword_ctx {
   int                 pvq_adapt[2*OD_NBSIZES*OD_NSB_ADAPT_CTXS];
   int                 pvq_k1_increment;
   /* CDFs are size 16 despite the fact that we're using less than that. */
-  uint16_t        pvq_k1_cdf[4][16];
+  uint16_t            pvq_k1_cdf[12][16];
+  uint16_t            pvq_split_cdf[14*7][8];
+  int                 pvq_split_increment;
 };
 
 struct od_pvq_adapt_ctx {
@@ -131,6 +133,8 @@ struct od_pvq_adapt_ctx {
 };
 
 void od_adapt_pvq_ctx_reset(od_pvq_adapt_ctx *state, int is_keyframe);
+int od_pvq_size_ctx(int n);
+int od_pvq_k1_ctx(int n, int orig_size);
 
 od_val16 od_pvq_sin(od_val32 x);
 od_val16 od_pvq_cos(od_val32 x);
index 663901f..203c2e1 100644 (file)
@@ -36,36 +36,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
 #include "partition.h"
 
 static void od_decode_pvq_codeword(od_ec_dec *ec, od_pvq_codeword_ctx *ctx,
- od_coeff *y, int n, int k, int noref, int bs) {
-  if (k == 1 && n < 16) {
-    int cdf_id;
-    int pos;
-    cdf_id = 2*(n == 15) + !noref;
-    OD_CLEAR(y, n);
-    pos = od_decode_cdf_adapt(ec, ctx->pvq_k1_cdf[cdf_id], n - !noref,
-     ctx->pvq_k1_increment, "pvq:k1");
-    y[pos] = 1;
-    if (od_ec_dec_bits(ec, 1, "pvq:k1")) y[pos] = -y[pos];
-  }
-  else {
-    int speed = 5;
-    int *pvq_adapt;
-    int adapt_curr[OD_NSB_ADAPT_CTXS] = { 0 };
-    pvq_adapt = ctx->pvq_adapt + 4*(2*bs + noref);
-    laplace_decode_vector(ec, y, n - !noref, k, adapt_curr,
-     pvq_adapt, "pvq:ktok");
-    if (adapt_curr[OD_ADAPT_K_Q8] > 0) {
-      pvq_adapt[OD_ADAPT_K_Q8] += (256*adapt_curr[OD_ADAPT_K_Q8]
-       - pvq_adapt[OD_ADAPT_K_Q8]) >> speed;
-      pvq_adapt[OD_ADAPT_SUM_EX_Q8] += (adapt_curr[OD_ADAPT_SUM_EX_Q8]
-       - pvq_adapt[OD_ADAPT_SUM_EX_Q8]) >> speed;
-    }
-    if (adapt_curr[OD_ADAPT_COUNT_Q8] > 0) {
-      pvq_adapt[OD_ADAPT_COUNT_Q8] += (adapt_curr[OD_ADAPT_COUNT_Q8]
-       - pvq_adapt[OD_ADAPT_COUNT_Q8]) >> speed;
-      pvq_adapt[OD_ADAPT_COUNT_EX_Q8] += (adapt_curr[OD_ADAPT_COUNT_EX_Q8]
-       - pvq_adapt[OD_ADAPT_COUNT_EX_Q8]) >> speed;
-    }
+ od_coeff *y, int n, int k) {
+  int i;
+  od_decode_band_pvq_splits(ec, ctx, y, n, k, 0);
+  for (i = 0; i < n; i++) {
+    if (y[i] && od_ec_dec_bits(ec, 1, "pvq:sign")) y[i] = -y[i];
   }
 }
 
@@ -139,7 +114,6 @@ typedef struct {
  * @param [in]     cdf_ctx selects which cdf context to use
  * @param [in,out] skip_rest whether to skip further bands in each direction
  * @param [in]     band    index of the band being decoded
- * @param [in]     bs      log of the block size minus 2
  * @param [in]     band    index of the band being decoded
  * @param [out]    skip    skip flag with range [0,1]
  * @param [in]     qm      QM with magnitude compensation
@@ -164,7 +138,6 @@ static void pvq_decode_partition(od_ec_dec *ec,
                                  int has_skip,
                                  int *skip_rest,
                                  int band,
-                                 int bs,
                                  int *skip,
                                  const int16_t *qm,
                                  const int16_t *qm_inv) {
@@ -291,7 +264,8 @@ static void pvq_decode_partition(od_ec_dec *ec,
   k = od_pvq_compute_k(qcg, itheta, theta, *noref, n, beta, nodesync);
   if (k != 0) {
     /* when noref==0, y is actually size n-1 */
-    od_decode_pvq_codeword(ec, &adapt->pvq.pvq_codeword_ctx, y, n, k, *noref, bs);
+    od_decode_pvq_codeword(ec, &adapt->pvq.pvq_codeword_ctx, y, n - !*noref,
+     k);
   }
   else {
     OD_CLEAR(y, n);
@@ -379,7 +353,7 @@ void od_pvq_decode(daala_dec_ctx *dec,
        model, &dec->state.adapt, exg + i, ext + i, ref + off[i], out + off[i],
        &noref[i], beta[i], robust, is_keyframe, pli,
        (pli != 0)*OD_NBSIZES*PVQ_MAX_PARTITIONS + bs*PVQ_MAX_PARTITIONS + i,
-       &cfl, i == 0 && (i < nb_bands - 1), skip_rest, i, bs, &skip[i],
+       &cfl, i == 0 && (i < nb_bands - 1), skip_rest, i, &skip[i],
        qm + off[i], qm_inv + off[i]);
       if (i == 0 && !skip_rest[0] && bs > 0) {
         int skip_dir;
index 2f21cc6..63bcc3e 100644 (file)
@@ -30,6 +30,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
 # include "entdec.h"
 # include "decint.h"
 
+void od_decode_band_pvq_splits(od_ec_dec *ec, od_pvq_codeword_ctx *adapt,
+ od_coeff *y, int n, int k, int level);
+
 #if OD_ACCOUNTING
 # define laplace_decode_special(dec, decay, max, str) laplace_decode_special_(dec, decay, max, str)
 # define laplace_decode(dec, ex_q8, k, str) laplace_decode_(dec, ex_q8, k, str)
index 0443868..57f7cc3 100644 (file)
@@ -42,44 +42,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
 #define OD_CFL_FLIP_SHIFT (OD_LIMIT_BSIZE_MAX + 0)
 
 static void od_encode_pvq_codeword(od_ec_enc *ec, od_pvq_codeword_ctx *adapt,
- const od_coeff *in, int n, int k, int noref, int bs) {
-  if (k == 1 && n < 16) {
-    int cdf_id;
-    int i;
-    int pos;
-    cdf_id = 2*(n == 15) + !noref;
-    pos = 32;
-    for (i = 0; i < n - !noref; i++) {
-      if (in[i]) {
-        pos = i;
-        break;
-      }
-    }
-    OD_ASSERT(pos < n - !noref);
-    od_encode_cdf_adapt(ec, pos, adapt->pvq_k1_cdf[cdf_id], n - !noref,
-     adapt->pvq_k1_increment);
-    od_ec_enc_bits(ec, in[pos] < 0, 1);
-  }
-  else {
-    int speed = 5;
-    int *pvq_adapt;
-    int adapt_curr[OD_NSB_ADAPT_CTXS] = { 0 };
-    pvq_adapt = adapt->pvq_adapt + 4*(2*bs + noref);
-    laplace_encode_vector(ec, in, n - !noref, k, adapt_curr,
-     pvq_adapt);
-    if (adapt_curr[OD_ADAPT_K_Q8] > 0) {
-      pvq_adapt[OD_ADAPT_K_Q8] += (256*adapt_curr[OD_ADAPT_K_Q8]
-       - pvq_adapt[OD_ADAPT_K_Q8]) >> speed;
-      pvq_adapt[OD_ADAPT_SUM_EX_Q8] += (adapt_curr[OD_ADAPT_SUM_EX_Q8]
-       - pvq_adapt[OD_ADAPT_SUM_EX_Q8]) >> speed;
-    }
-    if (adapt_curr[OD_ADAPT_COUNT_Q8] > 0) {
-      pvq_adapt[OD_ADAPT_COUNT_Q8] += (adapt_curr[OD_ADAPT_COUNT_Q8]
-       - pvq_adapt[OD_ADAPT_COUNT_Q8]) >> speed;
-      pvq_adapt[OD_ADAPT_COUNT_EX_Q8] += (adapt_curr[OD_ADAPT_COUNT_EX_Q8]
-       - pvq_adapt[OD_ADAPT_COUNT_EX_Q8]) >> speed;
-    }
-  }
+ const od_coeff *in, int n, int k) {
+  int i;
+  od_encode_band_pvq_splits(ec, adapt, in, n, k, 0);
+  for (i = 0; i < n; i++) if (in[i]) od_ec_enc_bits(ec, in[i] < 0, 1);
 }
 
 /* Computes 1/sqrt(i) using a table for small values. */
@@ -250,7 +216,7 @@ int od_vector_is_null(const od_coeff *x, int len) {
 
 static double od_pvq_rate(int qg, int icgr, int theta, int ts,
  const od_adapt_ctx *adapt, const od_coeff *y0, int k, int n,
- int is_keyframe, int pli, int bs) {
+ int is_keyframe, int pli) {
   double rate;
 #if OD_PVQ_RATE_APPROX
   /* Estimates the number of bits it will cost to encode K pulses in
@@ -267,7 +233,7 @@ static double od_pvq_rate(int qg, int icgr, int theta, int ts,
     od_ec_enc_init(&ec, 1000);
     OD_COPY(&cd, &adapt->pvq.pvq_codeword_ctx, 1);
     tell = od_ec_enc_tell_frac(&ec);
-    od_encode_pvq_codeword(&ec, &cd, y0, n, k, theta == -1, bs);
+    od_encode_pvq_codeword(&ec, &cd, y0, n - (theta != -1), k);
     rate = (od_ec_enc_tell_frac(&ec)-tell)/8.;
     od_ec_enc_clear(&ec);
   }
@@ -306,7 +272,6 @@ static double od_pvq_rate(int qg, int icgr, int theta, int ts,
  * @param [in]     is_keyframe whether we're encoding a keyframe
  * @param [in]     pli       plane index
  * @param [in]     adapt     probability adaptation context
- * @param [in]     bs        log of the block size minus two
  * @param [in]     qm        QM with magnitude compensation
  * @param [in]     qm_inv    Inverse of QM with magnitude compensation
  * @return         gain      index of the quatized gain
@@ -314,7 +279,7 @@ static double od_pvq_rate(int qg, int icgr, int theta, int ts,
 static int pvq_theta(od_coeff *out, const od_coeff *x0, const od_coeff *r0,
  int n, int q0, od_coeff *y, int *itheta, int *max_theta, int *vk,
  double beta, double *skip_diff, int robust, int is_keyframe, int pli,
- const od_adapt_ctx *adapt, int bs, const int16_t *qm,
+ const od_adapt_ctx *adapt, const int16_t *qm,
  const int16_t *qm_inv) {
   od_val32 g;
   od_val32 gr;
@@ -399,7 +364,7 @@ static int pvq_theta(od_coeff *out, const od_coeff *x0, const od_coeff *r0,
   dist = gain_weight*cg*cg*OD_CGAIN_SCALE_2;
   best_dist = dist;
   best_cost = dist + lambda*od_pvq_rate(0, 0, -1, 0, adapt, NULL, 0, n,
-   is_keyframe, pli, bs);
+   is_keyframe, pli);
   noref = 1;
   best_k = 0;
   *itheta = -1;
@@ -426,7 +391,7 @@ static int pvq_theta(od_coeff *out, const od_coeff *x0, const od_coeff *r0,
       best_dist *= OD_CGAIN_SCALE_2;
     }
     best_cost = best_dist + lambda*od_pvq_rate(0, icgr, 0, 0, adapt, NULL,
-     0, n, is_keyframe, pli, bs);
+     0, n, is_keyframe, pli);
     best_qtheta = 0;
     *itheta = 0;
     *max_theta = 0;
@@ -475,7 +440,7 @@ static int pvq_theta(od_coeff *out, const od_coeff *x0, const od_coeff *r0,
         dist *= OD_CGAIN_SCALE_2;
         /* Do approximate RDO. */
         cost = dist + lambda*od_pvq_rate(i, icgr, j, ts, adapt, y_tmp, k, n,
-         is_keyframe, pli, bs);
+         is_keyframe, pli);
         if (cost < best_cost) {
           best_cost = cost;
           best_dist = dist;
@@ -513,7 +478,7 @@ static int pvq_theta(od_coeff *out, const od_coeff *x0, const od_coeff *r0,
       dist *= OD_CGAIN_SCALE_2;
       /* Do approximate RDO. */
       cost = dist + lambda*od_pvq_rate(i, 0, -1, 0, adapt, y_tmp, k, n,
-       is_keyframe, pli, bs);
+       is_keyframe, pli);
       if (cost <= best_cost) {
         best_cost = cost;
         best_dist = dist;
@@ -577,7 +542,6 @@ static int pvq_theta(od_coeff *out, const od_coeff *x0, const od_coeff *r0,
  * @param [in]     is_keyframe whether we're encoding a keyframe
  * @param [in]     code_skip  whether the "skip rest" flag is allowed
  * @param [in]     skip_rest  when set, we skip all higher bands
- * @param [in]     bs         log of the block size minus two
  * @param [in]     encode_flip whether we need to encode the CfL flip flag now
  * @param [in]     flip       value of the CfL flip flag
  */
@@ -597,7 +561,6 @@ static void pvq_encode_partition(od_ec_enc *ec,
                                  int is_keyframe,
                                  int code_skip,
                                  int skip_rest,
-                                 int bs,
                                  int encode_flip,
                                  int flip) {
   int noref;
@@ -636,7 +599,8 @@ static void pvq_encode_partition(od_ec_enc *ec,
      &tmp, 2);
     OD_IIR_DIADIC(*ext, theta << 16, 2);
   }
-  od_encode_pvq_codeword(ec, &adapt->pvq.pvq_codeword_ctx, in, n, k, theta == -1, bs);
+  od_encode_pvq_codeword(ec, &adapt->pvq.pvq_codeword_ctx, in,
+   n - (theta != -1), k);
 }
 
 /** Quantizes a scalar with rate-distortion optimization (RDO)
@@ -783,7 +747,7 @@ int od_pvq_encode(daala_enc_ctx *enc,
     qg[i] = pvq_theta(out + off[i], in + off[i], ref + off[i], size[i],
      q, y + off[i], &theta[i], &max_theta[i],
      &k[i], beta[i], &skip_diff, robust, is_keyframe, pli, &enc->state.adapt,
-     bs, qm + off[i], qm_inv + off[i]);
+     qm + off[i], qm_inv + off[i]);
   }
   od_encode_checkpoint(enc, &buf);
   if (is_keyframe) out[0] = 0;
@@ -830,7 +794,7 @@ int od_pvq_encode(daala_enc_ctx *enc,
        size[i], k[i], model, &enc->state.adapt, exg + i, ext + i,
        robust || is_keyframe, (pli != 0)*OD_NBSIZES*PVQ_MAX_PARTITIONS
        + bs*PVQ_MAX_PARTITIONS + i, is_keyframe, i == 0 && (i < nb_bands - 1),
-       skip_rest, bs, encode_flip, flip);
+       skip_rest, encode_flip, flip);
     }
     if (i == 0 && !skip_rest && bs > 0) {
       od_encode_cdf_adapt(&enc->ec, skip_dir,
index 5c0829d..b010a7e 100644 (file)
@@ -30,6 +30,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
 # include "entenc.h"
 # include "encint.h"
 
+void od_encode_band_pvq_splits(od_ec_enc *ec, od_pvq_codeword_ctx *adapt,
+ const int *y, int n, int k, int level);
+
 void laplace_encode_special(od_ec_enc *enc, int x, unsigned decay, int max);
 void laplace_encode(od_ec_enc *enc, int x, int ex_q8, int k);
 void laplace_encode_vector(od_ec_enc *enc, const od_coeff *y, int n, int k,