WIP: lv_map_multi: New experiment

This experiment modifies lv_map to make use of multi symbol.

Replace the nz_map and coeff_base binary CDF with a new multi-symbol
CDF of size 4. The new base_cdf indicates for each coeff if the level
is 0, 1, 2 or >2. Two new special contexts are added to be used for the
last coefficient (the EOB coeff). For the EOB coefficient we already know
that it is non-zero. We use one context for DC EOB and one for AC EOB
(this can potentially be refined more).

The new symbol is read/written by special bitreader/bitwriter functions.
Those functions reduce the probability precision from 15bit to 9bit before
the invocation of the arithmetic coding engine.

The adapted symbol count is significantly reduced by this experiment.
E.g. for the I-frame of ducks_take_off at cq=12, the number of adapted symbols
is reduced from 6.7M to 4.3M.

Change-Id: Ifc3927d81ad044fb9b0733f1e54d713cb71a1572
diff --git a/aom_dsp/bitreader.h b/aom_dsp/bitreader.h
index 7f8d2ca..5d8e3b4 100644
--- a/aom_dsp/bitreader.h
+++ b/aom_dsp/bitreader.h
@@ -53,6 +53,10 @@
 #if CONFIG_LV_MAP
 #define aom_read_bin(r, cdf, nsymbs, ACCT_STR_NAME) \
   aom_read_bin_(r, cdf, nsymbs ACCT_STR_ARG(ACCT_STR_NAME))
+#if CONFIG_LV_MAP_MULTI
+#define aom_read_symbol4(r, cdf, nsymbs, ACCT_STR_NAME) \
+  aom_read_symbol4_(r, cdf, nsymbs ACCT_STR_ARG(ACCT_STR_NAME))
+#endif
 #endif
 
 #ifdef __cplusplus
@@ -211,8 +215,35 @@
   this_cdf[0] = clamp(this_cdf[0], (1 << 8), (127 << 8));
   ret = aom_read_cdf(r, this_cdf, nsymbs, ACCT_STR_NAME);
   if (r->allow_update_cdf) update_bin(cdf, ret, nsymbs);
+  // printf("bin: %d\n", this_cdf[0]);
   return ret;
 }
+
+#if CONFIG_LV_MAP_MULTI
+#define CDF_SYM4_BITS (9)
+static INLINE int aom_read_symbol4_(aom_reader *r, aom_cdf_prob *cdf,
+                                    int nsymbs ACCT_STR_PARAM) {
+  int ret;
+  const int shift = 15 - CDF_SYM4_BITS;
+  const int mask = ~((1 << shift) - 1);
+  const int min_prob = 1 << shift;
+  const int max_prob = 32767 & mask;
+  aom_cdf_prob this_cdf[5];
+  this_cdf[2] = AOMMAX(cdf[2] & mask, min_prob);
+  this_cdf[1] = AOMMAX(cdf[1] & mask, this_cdf[2] + min_prob);
+  this_cdf[0] = AOMMAX(cdf[0] & mask, this_cdf[1] + min_prob);
+  this_cdf[0] = AOMMIN(this_cdf[0], max_prob);
+  this_cdf[1] = AOMMIN(this_cdf[1], this_cdf[0] - min_prob);
+  this_cdf[2] = AOMMIN(this_cdf[2], this_cdf[1] - min_prob);
+  this_cdf[3] = 0;
+  this_cdf[4] = 0;
+  // printf("cdf: %5d %5d %5d\n", cdf[0], cdf[1], cdf[2]);
+  // printf("newcdf: %5d %5d %5d\n", this_cdf[0], this_cdf[1], this_cdf[2]);
+  ret = aom_read_cdf(r, this_cdf, nsymbs, ACCT_STR_NAME);
+  if (r->allow_update_cdf) update_cdf(cdf, ret, nsymbs);
+  return ret;
+}
+#endif
 #endif
 
 static INLINE int aom_read_tree_as_cdf(aom_reader *r,
diff --git a/aom_dsp/bitwriter.h b/aom_dsp/bitwriter.h
index 8677663..da57a52 100644
--- a/aom_dsp/bitwriter.h
+++ b/aom_dsp/bitwriter.h
@@ -145,6 +145,32 @@
   this_cdf[0] = clamp(this_cdf[0], (1 << 8), (127 << 8));
   aom_write_cdf(w, symb, this_cdf, nsymbs);
   if (w->allow_update_cdf) update_bin(cdf, symb, nsymbs);
+  // printf("bin: %d\n", this_cdf[0]);
+}
+#endif
+
+#if CONFIG_LV_MAP_MULTI
+#define CDF_SYM4_BITS (9)
+static INLINE void aom_write_cdf4(aom_writer *w, int symb, aom_cdf_prob *cdf,
+                                  int nsymbs) {
+  assert(nsymbs == 4);
+  const int shift = 15 - CDF_SYM4_BITS;
+  const int mask = ~((1 << shift) - 1);
+  const int min_prob = 1 << shift;
+  const int max_prob = 32767 & mask;
+  aom_cdf_prob this_cdf[5];
+  this_cdf[2] = AOMMAX(cdf[2] & mask, min_prob);
+  this_cdf[1] = AOMMAX(cdf[1] & mask, this_cdf[2] + min_prob);
+  this_cdf[0] = AOMMAX(cdf[0] & mask, this_cdf[1] + min_prob);
+  this_cdf[0] = AOMMIN(this_cdf[0], max_prob);
+  this_cdf[1] = AOMMIN(this_cdf[1], this_cdf[0] - min_prob);
+  this_cdf[2] = AOMMIN(this_cdf[2], this_cdf[1] - min_prob);
+  this_cdf[3] = 0;
+  this_cdf[4] = 0;
+  // printf("cdf: %5d %5d %5d\n", cdf[0], cdf[1], cdf[2]);
+  // printf("newcdf: %5d %5d %5d\n", this_cdf[0], this_cdf[1], this_cdf[2]);
+  aom_write_cdf(w, symb, this_cdf, nsymbs);
+  if (w->allow_update_cdf) update_bin(cdf, symb, nsymbs);
 }
 #endif
 
diff --git a/av1/common/entropy.c b/av1/common/entropy.c
index d640463..dd2177a 100644
--- a/av1/common/entropy.c
+++ b/av1/common/entropy.c
@@ -1611,7 +1611,6 @@
 void av1_average_tile_coef_cdfs(FRAME_CONTEXT *fc, FRAME_CONTEXT *ec_ctxs[],
                                 aom_cdf_prob *cdf_ptr[], int num_tiles) {
   int i, cdf_size;
-
   aom_cdf_prob *fc_cdf_ptr;
 #if CONFIG_SIMPLE_BWD_ADAPT
   assert(num_tiles == 1);
@@ -1619,11 +1618,17 @@
 
 #if CONFIG_LV_MAP
   AVERAGE_TILE_CDFS(txb_skip_cdf)
+#if CONFIG_LV_MAP_MULTI
+  AVERAGE_TILE_CDFS(coeff_base_cdf)
+#else
   AVERAGE_TILE_CDFS(nz_map_cdf)
+#endif
   AVERAGE_TILE_CDFS(eob_flag_cdf)
   AVERAGE_TILE_CDFS(eob_extra_cdf)
   AVERAGE_TILE_CDFS(dc_sign_cdf)
+#if !CONFIG_LV_MAP_MULTI
   AVERAGE_TILE_CDFS(coeff_base_cdf)
+#endif
   AVERAGE_TILE_CDFS(coeff_lps_cdf)
   AVERAGE_TILE_CDFS(coeff_br_cdf)
 #if CONFIG_CTX1D
diff --git a/av1/common/entropy.h b/av1/common/entropy.h
index 39c3db3..33ec743 100644
--- a/av1/common/entropy.h
+++ b/av1/common/entropy.h
@@ -74,12 +74,18 @@
 
 #define SIG_COEF_CONTEXTS_2D 26
 #define SIG_COEF_CONTEXTS_1D 16
+#if CONFIG_LV_MAP_MULTI
+#define SIG_COEF_CONTEXTS_EOB 2
+#define SIG_COEF_CONTEXTS \
+  (SIG_COEF_CONTEXTS_2D + SIG_COEF_CONTEXTS_1D + SIG_COEF_CONTEXTS_EOB)
+#else
 #if USE_CAUSAL_BASE_CTX
 #define SIG_COEF_CONTEXTS (SIG_COEF_CONTEXTS_2D + SIG_COEF_CONTEXTS_1D)
 #else  // USE_CAUSAL_BASE_CTX
 #define SIG_COEF_CONTEXTS \
   (SIG_COEF_CONTEXTS_2D + SIG_COEF_CONTEXTS_1D + SIG_COEF_CONTEXTS_1D)
 #endif  // USE_CAUSAL_BASE_CTX
+#endif
 
 #if USE_CAUSAL_BASE_CTX
 #define COEFF_BASE_CONTEXTS (SIG_COEF_CONTEXTS)
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 6eac13b..33f351e 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -31,6 +31,102 @@
   { 125, 102, 147 }, { 119, 101, 135 },
 };
 
+#if CONFIG_LV_MAP_MULTI
+const aom_prob default_coeff_base
+    [TX_SIZES][PLANE_TYPES][NUM_BASE_LEVELS][COEFF_BASE_CONTEXTS] = {
+      { { { 139, 242, 199, 135, 87,  51,  245, 208, 138, 89,  60,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 240,
+            200, 108, 70,  56,  230, 199, 126, 66,  32,  242, 204,
+            128, 74,  45,  241, 203, 120, 62,  128, 128, 139, 242 },
+          { 118, 230, 197, 147, 103, 60,  228, 202, 154, 110, 72,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 213,
+            196, 134, 94,  58,  199, 184, 130, 82,  40,  217, 186,
+            134, 86,  57,  204, 185, 127, 74,  128, 128, 118, 230 } },
+        { { 203, 248, 223, 170, 105, 58,  252, 235, 195, 125, 72,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 253,
+            244, 209, 110, 85,  128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 203, 248 },
+          { 170, 239, 210, 163, 112, 68,  239, 219, 175, 127, 84,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 246,
+            234, 184, 142, 154, 128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 170, 239 } } },
+      { { { 119, 240, 196, 136, 90,  50,  247, 214, 159, 109, 64,
+            241, 201, 137, 91,  53,  239, 199, 136, 89,  52,  251,
+            230, 176, 121, 76,  231, 202, 142, 84,  39,  246, 221,
+            169, 111, 61,  248, 221, 152, 97,  60,  128, 119, 240 },
+          { 98,  209, 182, 140, 100, 56,  234, 207, 166, 122, 73,
+            215, 189, 142, 103, 59,  216, 188, 140, 99,  59,  235,
+            216, 179, 137, 88,  214, 189, 141, 96,  46,  224, 200,
+            159, 117, 68,  221, 199, 152, 108, 68,  128, 98,  209 } },
+        { { 195, 245, 212, 159, 108, 64,  251, 231, 186, 131, 80,
+            250, 228, 175, 108, 58,  244, 213, 163, 120, 82,  254,
+            245, 216, 159, 91,  128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 195, 245 },
+          { 150, 207, 199, 164, 121, 76,  239, 221, 185, 142, 89,
+            231, 208, 162, 113, 69,  228, 205, 169, 136, 95,  246,
+            235, 204, 157, 110, 128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 150, 207 } } },
+      { { { 93,  232, 185, 124, 81,  38,  244, 206, 147, 98,  53,
+            246, 210, 150, 100, 54,  244, 208, 146, 94,  44,  253,
+            236, 189, 135, 82,  228, 195, 130, 76,  35,  242, 220,
+            170, 114, 59,  253, 235, 184, 122, 68,  128, 93,  232 },
+          { 80,  203, 169, 127, 86,  41,  228, 194, 151, 108, 58,
+            221, 195, 152, 110, 60,  220, 194, 149, 103, 48,  238,
+            221, 188, 147, 92,  205, 184, 130, 85,  41,  208, 195,
+            159, 120, 62,  233, 212, 173, 126, 76,  128, 80,  203 } },
+        { { 187, 239, 199, 149, 109, 66,  250, 226, 179, 130, 82,
+            248, 218, 159, 100, 63,  251, 227, 184, 135, 91,  254,
+            241, 202, 150, 99,  128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 187, 239 },
+          { 130, 202, 169, 146, 118, 73,  236, 217, 186, 146, 91,
+            215, 194, 154, 102, 77,  234, 216, 188, 145, 98,  245,
+            229, 201, 163, 110, 128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 130, 202 } } },
+      { { { 102, 225, 171, 113, 74,  33,  243, 201, 139, 92,  44,
+            244, 208, 146, 99,  53,  247, 214, 158, 107, 52,  253,
+            233, 183, 131, 73,  128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 102, 225 },
+          { 80,  190, 152, 116, 79,  34,  222, 187, 142, 101, 47,
+            211, 187, 148, 106, 56,  221, 200, 163, 118, 56,  236,
+            215, 181, 140, 78,  128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 80,  190 } },
+        { { 166, 237, 184, 144, 106, 62,  245, 211, 167, 129, 93,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 254,
+            240, 205, 158, 112, 128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 166, 237 },
+          { 91,  185, 133, 105, 95,  60,  213, 190, 164, 131, 107,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 242,
+            227, 203, 160, 127, 128, 128, 128, 128, 128, 128, 128,
+            128, 128, 128, 128, 128, 128, 128, 128, 128, 91,  185 } } }
+    };
+
+const aom_prob default_nz_map[TX_SIZES][PLANE_TYPES][SIG_COEF_CONTEXTS] = {
+  { { 59,  183, 130, 76,  48,  28,  202, 153, 84, 54, 34,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 200, 163, 84, 61, 34,  182, 131, 71,  31,
+      16,  210, 156, 78,  36,  26,  220, 170, 73, 32, 128, 128, 1,   1 },
+    { 96,  209, 171, 109, 59,  28,  223, 187, 128, 71,  35,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 215, 192, 135, 63,  73,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 1,   1 } },
+  { { 49, 190, 129, 74,  46, 25, 206, 150, 90,  55, 32, 205, 142, 79, 48,
+      27, 191, 137, 78,  47, 27, 223, 181, 109, 63, 37, 204, 136, 82, 42,
+      19, 226, 169, 106, 58, 30, 231, 180, 96,  49, 29, 128, 1,   1 },
+    { 86,  210, 159, 90,  56,  34,  223, 181, 114, 69,  40,  229, 182, 113, 59,
+      28,  218, 162, 96,  64,  42,  237, 207, 146, 92,  50,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 1,   1 } },
+  { { 41, 187, 119, 66,  40, 20, 212, 144, 80,  49, 26, 226, 151, 84, 49,
+      27, 214, 146, 82,  47, 22, 237, 190, 115, 68, 40, 206, 126, 71, 37,
+      17, 227, 168, 103, 61, 29, 237, 197, 119, 63, 32, 128, 1,   1 },
+    { 70,  207, 146, 82,  54,  35,  226, 167, 99,  65,  40,  238, 176, 96,  57,
+      29,  229, 171, 108, 69,  47,  244, 201, 124, 78,  48,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 1,   1 } },
+  { { 40,  176, 107, 57,  37,  16,  216, 136, 73,  44,  22,  235, 145, 79,  49,
+      26,  227, 149, 84,  52,  26,  247, 195, 107, 64,  35,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 1,   1 },
+    { 49,  210, 153, 95,  58,  31,  217, 151, 93,  64,  41,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 248, 197, 123, 79,  53,  128, 128, 128, 128,
+      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 1,   1 } }
+};
+#else  // CONFIG_LV_MAP_MULTI
 #if USE_CAUSAL_BASE_CTX
 const aom_prob default_coeff_base
     [TX_SIZES][PLANE_TYPES][NUM_BASE_LEVELS][COEFF_BASE_CONTEXTS] = {
@@ -239,6 +335,7 @@
           128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
           128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } } };
 #endif  // USE_CAUSAL_BASE_CTX
+#endif  // CONFIG_LV_MAP_MULTI
 
 #if CONFIG_CTX1D
 const aom_prob default_eob_flag[TX_SIZES][PLANE_TYPES][EOB_COEF_CONTEXTS] = {
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 1925d24..7e86fa6 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -152,15 +152,22 @@
 #endif  // CONFIG_CTX1D
 
   aom_cdf_prob txb_skip_cdf[TX_SIZES][TXB_SKIP_CONTEXTS][CDF_SIZE(2)];
+#if CONFIG_LV_MAP_MULTI
+  aom_cdf_prob coeff_base_cdf[TX_SIZES][PLANE_TYPES][SIG_COEF_CONTEXTS]
+                             [CDF_SIZE(4)];
+#else
   aom_cdf_prob nz_map_cdf[TX_SIZES][PLANE_TYPES][SIG_COEF_CONTEXTS]
                          [CDF_SIZE(2)];
+#endif
   aom_cdf_prob eob_flag_cdf[TX_SIZES][PLANE_TYPES][EOB_COEF_CONTEXTS]
                            [CDF_SIZE(2)];
   aom_cdf_prob eob_extra_cdf[TX_SIZES][PLANE_TYPES][EOB_COEF_CONTEXTS]
                             [CDF_SIZE(2)];
   aom_cdf_prob dc_sign_cdf[PLANE_TYPES][DC_SIGN_CONTEXTS][CDF_SIZE(2)];
+#if !CONFIG_LV_MAP_MULTI
   aom_cdf_prob coeff_base_cdf[TX_SIZES][PLANE_TYPES][NUM_BASE_LEVELS]
                              [COEFF_BASE_CONTEXTS][CDF_SIZE(2)];
+#endif
   aom_cdf_prob coeff_lps_cdf[TX_SIZES][PLANE_TYPES][LEVEL_CONTEXTS]
                             [CDF_SIZE(2)];
   aom_cdf_prob coeff_br_cdf[TX_SIZES][PLANE_TYPES][BASE_RANGE_SETS]
diff --git a/av1/common/txb_common.c b/av1/common/txb_common.c
index a4dc779..836d44d 100644
--- a/av1/common/txb_common.c
+++ b/av1/common/txb_common.c
@@ -98,7 +98,7 @@
 
 void av1_init_txb_probs(FRAME_CONTEXT *fc) {
   TX_SIZE tx_size;
-  int plane, ctx, level;
+  int plane, ctx;
 
   // Update probability models for transform block skip flag
   for (tx_size = 0; tx_size < TX_SIZES; ++tx_size) {
@@ -119,10 +119,11 @@
     }
   }
 
+#if !CONFIG_LV_MAP_MULTI
   // Update probability models for non-zero coefficient map and eob flag.
   for (tx_size = 0; tx_size < TX_SIZES; ++tx_size) {
     for (plane = 0; plane < PLANE_TYPES; ++plane) {
-      for (level = 0; level < NUM_BASE_LEVELS; ++level) {
+      for (int level = 0; level < NUM_BASE_LEVELS; ++level) {
         for (ctx = 0; ctx < COEFF_BASE_CONTEXTS; ++ctx) {
           fc->coeff_base_cdf[tx_size][plane][level][ctx][0] = AOM_ICDF(
               128 * (aom_cdf_prob)fc->coeff_base[tx_size][plane][level][ctx]);
@@ -132,16 +133,27 @@
       }
     }
   }
+#endif
 
   for (tx_size = 0; tx_size < TX_SIZES; ++tx_size) {
     for (plane = 0; plane < PLANE_TYPES; ++plane) {
       for (ctx = 0; ctx < SIG_COEF_CONTEXTS; ++ctx) {
+#if CONFIG_LV_MAP_MULTI
+        int p = fc->nz_map[tx_size][plane][ctx] * 128;
+        fc->coeff_base_cdf[tx_size][plane][ctx][0] = AOM_ICDF(p);
+        p += ((32768 - p) * fc->coeff_base[tx_size][plane][0][ctx]) >> 8;
+        fc->coeff_base_cdf[tx_size][plane][ctx][1] = AOM_ICDF(p);
+        p += ((32768 - p) * fc->coeff_base[tx_size][plane][1][ctx]) >> 8;
+        fc->coeff_base_cdf[tx_size][plane][ctx][2] = AOM_ICDF(p);
+        fc->coeff_base_cdf[tx_size][plane][ctx][3] = AOM_ICDF(32768);
+        fc->coeff_base_cdf[tx_size][plane][ctx][4] = 0;
+#else
         fc->nz_map_cdf[tx_size][plane][ctx][0] =
             AOM_ICDF(128 * (aom_cdf_prob)fc->nz_map[tx_size][plane][ctx]);
         fc->nz_map_cdf[tx_size][plane][ctx][1] = AOM_ICDF(32768);
         fc->nz_map_cdf[tx_size][plane][ctx][2] = 0;
+#endif
       }
-
       for (ctx = 0; ctx < EOB_COEF_CONTEXTS; ++ctx) {
         fc->eob_flag_cdf[tx_size][plane][ctx][0] =
             AOM_ICDF(128 * (aom_cdf_prob)fc->eob_flag[tx_size][plane][ctx]);
diff --git a/av1/common/txb_common.h b/av1/common/txb_common.h
index 21b4abc..2043be6 100644
--- a/av1/common/txb_common.h
+++ b/av1/common/txb_common.h
@@ -440,7 +440,15 @@
 static INLINE int get_nz_map_ctx(const uint8_t *const levels,
                                  const int scan_idx, const int16_t *const scan,
                                  const int bwl, const int height,
+#if CONFIG_LV_MAP_MULTI
+                                 const TX_TYPE tx_type, const int is_eob) {
+#else
                                  const TX_TYPE tx_type) {
+#endif
+#if CONFIG_LV_MAP_MULTI
+  if (is_eob)
+    return scan[scan_idx] == 0 ? SIG_COEF_CONTEXTS - 2 : SIG_COEF_CONTEXTS - 1;
+#endif
   const int coeff_idx = scan[scan_idx];
   const int row = coeff_idx >> bwl;
   const int col = coeff_idx - (row << bwl);
diff --git a/av1/decoder/decodetxb.c b/av1/decoder/decodetxb.c
index e0a1c76..a89e39c 100644
--- a/av1/decoder/decodetxb.c
+++ b/av1/decoder/decodetxb.c
@@ -82,9 +82,9 @@
   int all_zero = av1_read_record_bin(
       counts, r, ec_ctx->txb_skip_cdf[txs_ctx][txb_ctx->txb_skip_ctx], 2,
       ACCT_STR);
+  // printf("txb_skip: %d %2d\n", txs_ctx, txb_ctx->txb_skip_ctx);
   if (xd->counts)
     ++xd->counts->txb_skip[txs_ctx][txb_ctx->txb_skip_ctx][all_zero];
-
   *eob = 0;
   if (all_zero) {
     *max_scan_line = 0;
@@ -124,7 +124,7 @@
     is_equal = av1_read_record_bin(
         counts, r, ec_ctx->eob_flag_cdf[txs_ctx][plane_type][eob_pos_ctx], 2,
         ACCT_STR);
-
+    // printf("eob_flag_cdf: %d %d %2d\n", txs_ctx, plane_type, eob_pos_ctx);
     // aom_read_symbol(r,
     // ec_ctx->eob_flag_cdf[AOMMIN(txs_ctx,3)][plane_type][eob_pos_ctx], 2,
     // ACCT_STR);
@@ -145,6 +145,7 @@
     int bit = av1_read_record_bin(
         counts, r, ec_ctx->eob_extra_cdf[txs_ctx][plane_type][eob_pt], 2,
         ACCT_STR);
+    // printf("eob_extra_cdf: %d %d %2d\n", txs_ctx, plane_type, eob_pt);
     if (counts) ++counts->eob_extra[txs_ctx][plane_type][eob_pt][bit];
     if (bit) {
       eob_extra += (1 << eob_shift);
@@ -153,6 +154,7 @@
     for (int i = 1; i < k_eob_offset_bits[eob_pt]; i++) {
       eob_shift = k_eob_offset_bits[eob_pt] - 1 - i;
       bit = av1_read_record_bit(counts, r, ACCT_STR);
+      // printf("eob_bit:\n");
       if (bit) {
         eob_extra += (1 << eob_shift);
       }
@@ -164,6 +166,22 @@
 
   for (int i = 0; i < *eob; ++i) {
     c = *eob - 1 - i;
+#if CONFIG_LV_MAP_MULTI
+    (void)nz_map_count;
+    int coeff_ctx =
+        get_nz_map_ctx(levels, c, scan, bwl, height, tx_type, c == *eob - 1);
+    int level = av1_read_record_symbol4(
+        counts, r, ec_ctx->coeff_base_cdf[txs_ctx][plane_type][coeff_ctx], 4,
+        ACCT_STR);
+    levels[get_paded_idx(scan[c], bwl)] = level;
+    // printf("base_cdf: %d %d %2d\n", txs_ctx, plane_type, coeff_ctx);
+    // printf("base_cdf: %d %d %2d : %3d %3d %3d\n", txs_ctx, plane_type,
+    // coeff_ctx,
+    //            ec_ctx->coeff_base_cdf[txs_ctx][plane_type][coeff_ctx][0]>>7,
+    //            ec_ctx->coeff_base_cdf[txs_ctx][plane_type][coeff_ctx][1]>>7,
+    //            ec_ctx->coeff_base_cdf[txs_ctx][plane_type][coeff_ctx][2]>>7);
+    if (level < 3) cul_level += level;
+#else
     int is_nz;
     int coeff_ctx = get_nz_map_ctx(levels, c, scan, bwl, height, tx_type);
 
@@ -199,6 +217,7 @@
       levels[get_paded_idx(scan[c], bwl)] = k + 1;
     }
 #endif
+#endif
   }
 
   *max_scan_line = *eob;
@@ -246,6 +265,7 @@
 #if LV_MAP_PROB
       *sign = av1_read_record_bin(
           counts, r, ec_ctx->dc_sign_cdf[plane_type][dc_sign_ctx], 2, ACCT_STR);
+// printf("dc_sign: %d %d\n", plane_type, dc_sign_ctx);
 #else
       *sign = aom_read(r, ec_ctx->dc_sign[plane_type][dc_sign_ctx], ACCT_STR);
 #endif
@@ -267,6 +287,7 @@
       ctx = get_br_ctx(levels, scan[c], bwl, level_counts[scan[c]]);
 
       for (idx = 0; idx < BASE_RANGE_SETS; ++idx) {
+        // printf("br: %d %d %d %d\n", txs_ctx, plane_type, idx, ctx);
         if (av1_read_record_bin(
                 counts, r, ec_ctx->coeff_br_cdf[txs_ctx][plane_type][idx][ctx],
                 2, ACCT_STR)) {
@@ -309,6 +330,9 @@
   for (c = 0; c < *eob; ++c) {
     const int16_t dqv = (c == 0) ? dequant[0] : dequant[1];
     const int level = levels[get_paded_idx(scan[c], bwl)];
+    // printf("level: %3d\n", level);
+    // printf("activity: %d %d %2d %3d\n", txs_ctx, plane_type, base_cul_level,
+    // level);
     const tran_low_t t = ((level + tcoeffs[scan[c]]) * dqv) >> shift;
 #if CONFIG_SYMBOLRATE
     av1_record_coeff(counts, level);
diff --git a/av1/decoder/symbolrate.h b/av1/decoder/symbolrate.h
index f6688a9..00816ac 100644
--- a/av1/decoder/symbolrate.h
+++ b/av1/decoder/symbolrate.h
@@ -40,6 +40,17 @@
   if (counts) ++counts->symbol_num[0];
   return aom_read_bin(r, cdf, nsymbs, str);
 }
+
+#if CONFIG_LV_MAP_MULTI
+static INLINE int av1_read_record_symbol4(FRAME_COUNTS *counts, aom_reader *r,
+                                          aom_cdf_prob *cdf, int nsymbs,
+                                          const char *str) {
+  (void)str;
+  if (counts) ++counts->symbol_num[0];
+  return aom_read_symbol4(r, cdf, nsymbs, str);
+}
+#endif
+
 #endif
 
 static INLINE int av1_read_record(FRAME_COUNTS *counts, aom_reader *r, int prob,
@@ -82,6 +93,10 @@
 #if CONFIG_LV_MAP
 #define av1_read_record_bin(counts, r, cdf, nsymbs, ACCT_STR_NAME) \
   aom_read_bin(r, cdf, nsymbs, ACCT_STR_NAME)
+#if CONFIG_LV_MAP_MULTI
+#define av1_read_record_symbol4(counts, r, cdf, nsymbs, ACCT_STR_NAME) \
+  aom_read_symbol4(r, cdf, nsymbs, ACCT_STR_NAME)
+#endif
 #endif
 
 #define av1_read_record(counts, r, prob, ACCT_STR_NAME) \
diff --git a/av1/encoder/block.h b/av1/encoder/block.h
index b0d13d2..9c90299 100644
--- a/av1/encoder/block.h
+++ b/av1/encoder/block.h
@@ -63,11 +63,17 @@
 #if CONFIG_LV_MAP
 typedef struct {
   int txb_skip_cost[TXB_SKIP_CONTEXTS][2];
+#if CONFIG_LV_MAP_MULTI
+  int base_cost[SIG_COEF_CONTEXTS][4];
+#else
   int nz_map_cost[SIG_COEF_CONTEXTS][2];
+#endif
   int eob_cost[EOB_COEF_CONTEXTS][2];
   int eob_extra_cost[EOB_COEF_CONTEXTS][2];
   int dc_sign_cost[DC_SIGN_CONTEXTS][2];
+#if !CONFIG_LV_MAP_MULTI
   int base_cost[NUM_BASE_LEVELS][COEFF_BASE_CONTEXTS][2];
+#endif
   int lps_cost[LEVEL_CONTEXTS][COEFF_BASE_RANGE + 1];
   int br_cost[BASE_RANGE_SETS][LEVEL_CONTEXTS][2];
 #if CONFIG_CTX1D
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c
index 2ac2eac..37df7b2 100644
--- a/av1/encoder/encodetxb.c
+++ b/av1/encoder/encodetxb.c
@@ -190,10 +190,16 @@
 }
 
 static int get_coeff_cost(const tran_low_t qc, const int scan_idx,
+#if CONFIG_LV_MAP_MULTI
+                          const int is_eob,
+#endif
                           const TxbInfo *const txb_info,
                           const LV_MAP_COEFF_COST *const txb_costs);
 
 static void get_dist_cost_stats(LevelDownStats *stats, int scan_idx,
+#if CONFIG_LV_MAP_MULTI
+                                const int is_eob,
+#endif
                                 const LV_MAP_COEFF_COST *txb_costs,
                                 TxbInfo *txb_info) {
   const int16_t *scan = txb_info->scan_order->scan;
@@ -208,7 +214,11 @@
 
   const tran_low_t dqc = qcoeff_to_dqcoeff(qc, dqv, txb_info->shift);
   const int64_t dqc_dist = get_coeff_dist(tqc, dqc, txb_info->shift);
+#if CONFIG_LV_MAP_MULTI
+  const int qc_cost = get_coeff_cost(qc, scan_idx, is_eob, txb_info, txb_costs);
+#else
   const int qc_cost = get_coeff_cost(qc, scan_idx, txb_info, txb_costs);
+#endif
 
   // distortion difference when coefficient is quantized to 0
   const tran_low_t dqc0 = qcoeff_to_dqcoeff(0, dqv, txb_info->shift);
@@ -225,21 +235,35 @@
   stats->low_dqc = qcoeff_to_dqcoeff(stats->low_qc, dqv, txb_info->shift);
   const int64_t low_dqc_dist =
       get_coeff_dist(tqc, stats->low_dqc, txb_info->shift);
+#if CONFIG_LV_MAP_MULTI
+  const int low_qc_cost =
+      get_coeff_cost(stats->low_qc, scan_idx, is_eob, txb_info, txb_costs);
+#else
   const int low_qc_cost =
       get_coeff_cost(stats->low_qc, scan_idx, txb_info, txb_costs);
-
+#endif
   stats->dist_low = low_dqc_dist - stats->dist0;
   stats->rate_low = low_qc_cost;
   stats->rd_low = RDCOST(txb_info->rdmult, stats->rate_low, stats->dist_low);
 
+#if CONFIG_LV_MAP_MULTI
+  int coeff_ctx = get_nz_map_ctx(levels, scan_idx, scan, txb_info->bwl,
+                                 txb_info->height, txb_info->tx_type, is_eob);
+  if ((stats->rd_low < stats->rd) && (stats->low_qc == 0)) {
+    stats->nz_rate = txb_costs->base_cost[coeff_ctx][0];
+  } else {
+    // TODO(olah): revisit what non-zero cost should be used here
+    stats->nz_rate = txb_costs->base_cost[coeff_ctx][1];
+  }
+#else
   int coeff_ctx = get_nz_map_ctx(levels, scan_idx, scan, txb_info->bwl,
                                  txb_info->height, txb_info->tx_type);
-
   if ((stats->rd_low < stats->rd) && (stats->low_qc == 0)) {
     stats->nz_rate = txb_costs->nz_map_cost[coeff_ctx][0];
   } else {
     stats->nz_rate = txb_costs->nz_map_cost[coeff_ctx][1];
   }
+#endif
 }
 
 static INLINE void update_qcoeff(const int coeff_idx, const tran_low_t qc,
@@ -301,10 +325,8 @@
 
   (void)blk_row;
   (void)blk_col;
-
   aom_write_bin(w, eob == 0,
                 ec_ctx->txb_skip_cdf[txs_ctx][txb_ctx->txb_skip_ctx], 2);
-
   if (eob == 0) return;
 
   av1_txb_init_levels(tcoeff, width, height, levels);
@@ -349,8 +371,15 @@
   int coeff_ctx = 0;
   for (int i = 0; i < eob; ++i) {
     c = eob - 1 - i;
-    coeff_ctx = get_nz_map_ctx(levels, c, scan, bwl, height, tx_type);
 
+#if CONFIG_LV_MAP_MULTI
+    coeff_ctx =
+        get_nz_map_ctx(levels, c, scan, bwl, height, tx_type, c == eob - 1);
+    tran_low_t v = tcoeff[scan[c]];
+    aom_write_cdf4(w, AOMMIN(abs(v), 3),
+                   ec_ctx->coeff_base_cdf[txs_ctx][plane_type][coeff_ctx], 4);
+#else
+    coeff_ctx = get_nz_map_ctx(levels, c, scan, bwl, height, tx_type);
     tran_low_t v = tcoeff[scan[c]];
     int is_nz = (v != 0);
 
@@ -369,6 +398,7 @@
         if (is_k == 0) break;
       }
     }
+#endif
   }
   update_eob = eob - 1;
 #else
@@ -449,6 +479,7 @@
         br_set_idx = coeff_to_br_index[base_range];
 
       for (idx = 0; idx < BASE_RANGE_SETS; ++idx) {
+        // printf("br: %d %d %d %d\n", txs_ctx, plane_type, idx, ctx);
         aom_write_bin(w, idx == br_set_idx,
                       ec_ctx->coeff_br_cdf[txs_ctx][plane_type][idx][ctx], 2);
         if (idx == br_set_idx) {
@@ -623,6 +654,11 @@
     tran_low_t v = qcoeff[scan[c]];
     int is_nz = (v != 0);
     int level = abs(v);
+#if CONFIG_LV_MAP_MULTI
+    coeff_ctx =
+        get_nz_map_ctx(levels, c, scan, bwl, height, tx_type, c == eob - 1);
+    cost += coeff_costs->base_cost[coeff_ctx][AOMMIN(level, 3)];
+#else  // CONFIG_LV_MAP_MULTI
 #if USE_CAUSAL_BASE_CTX
     coeff_ctx = get_nz_map_ctx(levels, c, scan, bwl, height, tx_type);
 #endif
@@ -633,6 +669,7 @@
 #endif
       cost += coeff_costs->nz_map_cost[coeff_ctx][is_nz];
     }
+#endif  // CONFIG_LV_MAP_MULTI
 
     if (is_nz) {
 #if !USE_CAUSAL_BASE_CTX
@@ -647,6 +684,7 @@
       } else {
         cost += av1_cost_bit(128, sign);
       }
+#if !CONFIG_LV_MAP_MULTI
 #if USE_CAUSAL_BASE_CTX
       int k;
       for (k = 0; k < NUM_BASE_LEVELS; ++k) {
@@ -670,7 +708,7 @@
         cost += coeff_costs->base_cost[i][ctx_ls[i]][0];
       }
 #endif
-
+#endif  // CONFIG_LV_MAP_MULTI
       if (level > NUM_BASE_LEVELS) {
         int ctx;
         ctx = get_br_ctx(levels, scan[c], bwl, level_counts[scan[c]]);
@@ -794,6 +832,11 @@
 static INLINE const int *get_level_prob(int level, int coeff_idx,
                                         const TxbCache *txb_cache,
                                         const LV_MAP_COEFF_COST *txb_costs) {
+#if CONFIG_LV_MAP_MULTI
+  if (level < 1 + NUM_BASE_LEVELS) {
+    const int ctx = txb_cache->nz_ctx_arr[coeff_idx];
+    return &txb_costs->base_cost[ctx][level];
+#else
   if (level == 0) {
     const int ctx = txb_cache->nz_ctx_arr[coeff_idx];
     return txb_costs->nz_map_cost[ctx];
@@ -801,12 +844,13 @@
     const int idx = level - 1;
     const int ctx = txb_cache->base_ctx_arr[idx][coeff_idx];
     return txb_costs->base_cost[idx][ctx];
+#endif
   } else if (level >= 1 + NUM_BASE_LEVELS &&
              level < 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
     const int ctx = txb_cache->br_ctx_arr[coeff_idx];
     return txb_costs->lps_cost[ctx];
   } else if (level >= 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
-    printf("get_level_prob does not support golomb\n");
+    // printf("get_level_prob does not support golomb\n");
     assert(0);
     return 0;
   } else {
@@ -908,6 +952,15 @@
                                         const TxbCache *txb_cache,
                                         const LV_MAP_COEFF_COST *txb_costs,
                                         const TxbInfo *txb_info) {
+#if CONFIG_LV_MAP_MULTI
+  // TODO(olah): not implemented yet
+  (void)coeff_idx;
+  (void)nb_coeff_idx;
+  (void)txb_cache;
+  (void)txb_costs;
+  (void)txb_info;
+  return 0;
+#else
   const tran_low_t qc = txb_info->qcoeff[coeff_idx];
   const tran_low_t abs_qc = abs(qc);
   const BASE_CTX_TABLE *base_ctx_table =
@@ -943,6 +996,7 @@
     }
   }
   return cost_diff;
+#endif
 }
 
 static int try_neighbor_level_down_nz(int coeff_idx, int nb_coeff_idx,
@@ -971,9 +1025,14 @@
         txb_info->tx_type);
     update_qcoeff(nb_coeff_idx, nb_coeff, txb_info);
     const int ctx = txb_cache->nz_ctx_arr[coeff_idx];
+#if CONFIG_LV_MAP_MULTI
+    const int org_cost = txb_costs->base_cost[ctx][AOMMIN(abs_qc, 3)];
+    const int new_cost = txb_costs->base_cost[new_ctx][AOMMIN(abs_qc, 3)];
+#else
     const int is_nz = abs_qc > 0;
     const int org_cost = txb_costs->nz_map_cost[ctx][is_nz];
     const int new_cost = txb_costs->nz_map_cost[new_ctx][is_nz];
+#endif
     const int cost_diff = new_cost - org_cost;
     return cost_diff;
   } else {
@@ -1219,8 +1278,16 @@
   const int abs_qc = abs(qc);
   assert(abs_qc <= 1);
   int cost = 0;
-  const int scan_idx = txb_info->scan_order->iscan[coeff_idx];
 
+#if CONFIG_LV_MAP_MULTI
+  const int ctx = txb_cache->nz_ctx_arr[coeff_idx];
+  cost += txb_costs->base_cost[ctx][AOMMIN(abs_qc, 3)];
+  if (qc != 0) {
+    cost += get_sign_bit_cost(qc, coeff_idx, txb_costs->dc_sign_cost,
+                              txb_info->txb_ctx->dc_sign_ctx);
+  }
+#else
+  const int scan_idx = txb_info->scan_order->iscan[coeff_idx];
   if (scan_idx < txb_info->eob - 1) {
     const int *level_cost = get_level_prob(0, coeff_idx, txb_cache, txb_costs);
     cost += level_cost[qc != 0];
@@ -1234,6 +1301,7 @@
     cost += get_sign_bit_cost(qc, coeff_idx, txb_costs->dc_sign_cost,
                               txb_info->txb_ctx->dc_sign_ctx);
   }
+#endif
   return cost;
 }
 
@@ -1418,6 +1486,9 @@
 }
 
 static int get_coeff_cost(const tran_low_t qc, const int scan_idx,
+#if CONFIG_LV_MAP_MULTI
+                          const int is_eob,
+#endif
                           const TxbInfo *const txb_info,
                           const LV_MAP_COEFF_COST *const txb_costs) {
   const TXB_CTX *txb_ctx = txb_info->txb_ctx;
@@ -1426,12 +1497,17 @@
   int cost = 0;
   const int16_t *scan = txb_info->scan_order->scan;
 
+#if CONFIG_LV_MAP_MULTI
+  int coeff_ctx =
+      get_nz_map_ctx(txb_info->levels, scan_idx, scan, txb_info->bwl,
+                     txb_info->height, txb_info->tx_type, is_eob);
+  cost += txb_costs->base_cost[coeff_ctx][AOMMIN(abs_qc, 3)];
+#else
 #if USE_CAUSAL_BASE_CTX
   int coeff_ctx =
       get_nz_map_ctx(txb_info->levels, scan_idx, scan, txb_info->bwl,
                      txb_info->height, txb_info->tx_type);
 #endif
-
   if (scan_idx < txb_info->eob - 1) {
 #if !USE_CAUSAL_BASE_CTX
     int coeff_ctx =
@@ -1440,11 +1516,12 @@
 #endif
     cost += txb_costs->nz_map_cost[coeff_ctx][is_nz];
   }
-
+#endif
   if (is_nz) {
     cost += get_sign_bit_cost(qc, scan_idx, txb_costs->dc_sign_cost,
                               txb_ctx->dc_sign_ctx);
 
+#if !CONFIG_LV_MAP_MULTI
 #if USE_CAUSAL_BASE_CTX
     int k;
     for (k = 0; k < NUM_BASE_LEVELS; ++k) {
@@ -1464,7 +1541,7 @@
                             txb_costs->base_cost[i][ctx_ls[i]], i);
     }
 #endif
-
+#endif
     if (abs_qc > NUM_BASE_LEVELS) {
       const int row = scan[scan_idx] >> txb_info->bwl;
       const int col = scan[scan_idx] - (row << txb_info->bwl);
@@ -1507,7 +1584,12 @@
     if (nb_scan_idx < txb_info->eob && nb_row >= 0 && nb_col >= 0 &&
         nb_row < txb_info->height && nb_col < txb_info->width) {
       tran_low_t nb_coeff = txb_info->qcoeff[nb_coeff_idx];
+#if CONFIG_LV_MAP_MULTI
+      int cost =
+          get_coeff_cost(nb_coeff, nb_scan_idx, is_eob, txb_info, txb_costs);
+#else
       int cost = get_coeff_cost(nb_coeff, nb_scan_idx, txb_info, txb_costs);
+#endif
       if (cost_map)
         cost_map[nb_row - row + COST_MAP_OFFSET]
                 [nb_col - col + COST_MAP_OFFSET] -= cost;
@@ -1524,7 +1606,12 @@
     if (nb_scan_idx < txb_info->eob && nb_row >= 0 && nb_col >= 0 &&
         nb_row < txb_info->height && nb_col < txb_info->width) {
       tran_low_t nb_coeff = txb_info->qcoeff[nb_coeff_idx];
+#if CONFIG_LV_MAP_MULTI
+      int cost =
+          get_coeff_cost(nb_coeff, nb_scan_idx, is_eob, txb_info, txb_costs);
+#else
       int cost = get_coeff_cost(nb_coeff, nb_scan_idx, txb_info, txb_costs);
+#endif
       if (cost_map)
         cost_map[nb_row - row + COST_MAP_OFFSET]
                 [nb_col - col + COST_MAP_OFFSET] += cost;
@@ -1569,7 +1656,12 @@
   cost = txb_costs->txb_skip_cost[txb_skip_ctx][0];
   for (int c = 0; c < txb_info->eob; ++c) {
     tran_low_t qc = txb_info->qcoeff[scan[c]];
+#if CONFIG_LV_MAP_MULTI
+    int coeff_cost =
+        get_coeff_cost(qc, c, c == txb_info->eob - 1, txb_info, txb_costs);
+#else
     int coeff_cost = get_coeff_cost(qc, c, txb_info, txb_costs);
+#endif
     cost += coeff_cost;
   }
   return cost;
@@ -1711,7 +1803,11 @@
     tran_low_t qc = txb_info->qcoeff[coeff_idx];
 
     LevelDownStats stats;
+#if CONFIG_LV_MAP_MULTI
+    get_dist_cost_stats(&stats, si, si == init_eob - 1, txb_costs, txb_info);
+#else
     get_dist_cost_stats(&stats, si, txb_costs, txb_info);
+#endif
 
     if (qc == 0) {
       accu_rate += stats.rate;
@@ -1730,10 +1826,14 @@
         }
         txb_info->eob = si + 1;
 
+        // rerun cost calculation due to change of eob
         accu_rate = cur_eob_rate;
         accu_dist = 0;
-        // rerun cost calculation due to change of eob
+#if CONFIG_LV_MAP_MULTI
+        get_dist_cost_stats(&stats, si, 1, txb_costs, txb_info);
+#else
         get_dist_cost_stats(&stats, si, txb_costs, txb_info);
+#endif
       }
 
       int bUpdCoeff = 0;
@@ -2074,8 +2174,17 @@
     tran_low_t v = qcoeff[scan[c]];
     int is_nz = (v != 0);
 
-#if USE_CAUSAL_BASE_CTX
+#if CONFIG_LV_MAP_MULTI
+    (void)is_nz;
+    (void)nz_map_count;
+    coeff_ctx =
+        get_nz_map_ctx(levels, c, scan, bwl, height, tx_type, c == eob - 1);
+    update_cdf(ec_ctx->coeff_base_cdf[txsize_ctx][plane_type][coeff_ctx],
+               AOMMIN(abs(v), 3), 4);
+
+#elif USE_CAUSAL_BASE_CTX
     coeff_ctx = get_nz_map_ctx(levels, c, scan, bwl, height, tx_type);
+
     if (c < eob - 1) {
       ++(*nz_map_count)[coeff_ctx][is_nz];
       if (allow_update_cdf)
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index f74fac6..4b4de0d 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -542,10 +542,15 @@
         av1_cost_tokens_from_cdf(pcost->txb_skip_cost[ctx],
                                  fc->txb_skip_cdf[tx_size][ctx], NULL);
 
+#if CONFIG_LV_MAP_MULTI
+      for (int ctx = 0; ctx < SIG_COEF_CONTEXTS; ++ctx)
+        av1_cost_tokens_from_cdf(pcost->base_cost[ctx],
+                                 fc->coeff_base_cdf[tx_size][plane][ctx], NULL);
+#else
       for (int ctx = 0; ctx < SIG_COEF_CONTEXTS; ++ctx)
         av1_cost_tokens_from_cdf(pcost->nz_map_cost[ctx],
                                  fc->nz_map_cdf[tx_size][plane][ctx], NULL);
-
+#endif
       for (int ctx = 0; ctx < EOB_COEF_CONTEXTS; ++ctx)
         av1_cost_tokens_from_cdf(pcost->eob_cost[ctx],
                                  fc->eob_flag_cdf[tx_size][plane][ctx], NULL);
@@ -558,12 +563,13 @@
         av1_cost_tokens_from_cdf(pcost->dc_sign_cost[ctx],
                                  fc->dc_sign_cdf[plane][ctx], NULL);
 
+#if !CONFIG_LV_MAP_MULTI
       for (int layer = 0; layer < NUM_BASE_LEVELS; ++layer)
         for (int ctx = 0; ctx < COEFF_BASE_CONTEXTS; ++ctx)
           av1_cost_tokens_from_cdf(
               pcost->base_cost[layer][ctx],
               fc->coeff_base_cdf[tx_size][plane][layer][ctx], NULL);
-
+#endif
       for (int br = 0; br < BASE_RANGE_SETS; ++br)
         for (int ctx = 0; ctx < LEVEL_CONTEXTS; ++ctx)
           av1_cost_tokens_from_cdf(pcost->br_cost[br][ctx],
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index b587de1..20bfe17 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -162,6 +162,7 @@
 set(CONFIG_LOOP_RESTORATION 1 CACHE NUMBER "AV1 experiment flag.")
 set(CONFIG_LPF_SB 0 CACHE NUMBER "AV1 experiment flag.")
 set(CONFIG_LV_MAP 0 CACHE NUMBER "AV1 experiment flag.")
+set(CONFIG_LV_MAP_MULTI 0 CACHE NUMBER "AV1 experiment flag.")
 set(CONFIG_MASKED_TX 0 CACHE NUMBER "AV1 experiment flag.")
 set(CONFIG_MAX_TILE 0 CACHE NUMBER "AV1 experiment flag.")
 set(CONFIG_MFMV 0 CACHE NUMBER "AV1 experiment flag.")
diff --git a/build/cmake/aom_experiment_deps.cmake b/build/cmake/aom_experiment_deps.cmake
index 6e0c07d..9bbe22a 100644
--- a/build/cmake/aom_experiment_deps.cmake
+++ b/build/cmake/aom_experiment_deps.cmake
@@ -38,6 +38,12 @@
     endif ()
   endif ()
 
+  if (CONFIG_LV_MAP_MULTI)
+    if (NOT CONFIG_LV_MAP)
+      change_config_and_warn(CONFIG_LV_MAP 1 CONFIG_LV_MAP_MULTI)
+    endif ()
+  endif ()
+
   if (CONFIG_DAALA_TX)
      set(CONFIG_HIGHBITDEPTH 1)
      set(CONFIG_DAALA_TX4 1)
diff --git a/configure b/configure
index d0ac2c2..bf55937 100755
--- a/configure
+++ b/configure
@@ -299,6 +299,7 @@
     palette_throughput
     ref_adapt
     lv_map
+    lv_map_multi 
     ctx1d
     txk_sel
     mv_compress
@@ -536,6 +537,7 @@
     soft_enable tmv
 
     # Fix up experiment dependencies
+    enabled lv_map_multi && soft_enable lv_map
     enabled lv_map && disable_feature mrc_tx
     enabled eob_first && enable_feature lv_map
     enabled txk_sel && soft_enable lv_map