set number of values at runtime
diff --git a/tuple/include/array_of_doubles_sketch.hpp b/tuple/include/array_of_doubles_sketch.hpp
index b869470..cb1977e 100644
--- a/tuple/include/array_of_doubles_sketch.hpp
+++ b/tuple/include/array_of_doubles_sketch.hpp
@@ -29,24 +29,58 @@
 
 // equivalent of ArrayOfDoublesSketch in Java
 
-template<int num>
-struct array_of_doubles_update_policy {
-  std::array<double, num> create() const {
-    return std::array<double, num>();
+template<typename A = std::allocator<std::vector<double>>>
+class array_of_doubles_update_policy {
+public:
+  array_of_doubles_update_policy(uint8_t num_values = 1, const A& allocator = A()):
+    allocator(allocator), num_values(num_values) {}
+  std::vector<double> create() const {
+    return std::vector<double>(num_values, 0, allocator);
   }
-  void update(std::array<double, num>& summary, const std::array<double, num>& update) const {
-    for (int i = 0; i < num; ++i) summary[i] += update[i];
+  void update(std::vector<double>& summary, const std::vector<double>& update) const {
+    for (uint8_t i = 0; i < num_values; ++i) summary[i] += update[i];
   }
+  uint8_t get_num_values() const {
+    return num_values;
+  }
+
+private:
+  A allocator;
+  uint8_t num_values;
 };
 
-template<int num, typename A = std::allocator<std::array<double, num>>>
-using update_array_of_doubles_sketch = update_tuple_sketch<
-    std::array<double, num>, std::array<double, num>, array_of_doubles_update_policy<num>, A>;
+// forward declaration
+template<typename A> class compact_array_of_doubles_sketch;
 
-template<int num, typename A = std::allocator<std::array<double, num>>>
-class compact_array_of_doubles_sketch: public compact_tuple_sketch<std::array<double, num>, A> {
+template<typename A = std::allocator<std::vector<double>>>
+class update_array_of_doubles_sketch: public update_tuple_sketch<std::vector<double>, std::vector<double>,
+array_of_doubles_update_policy<A>, A> {
 public:
-  using Summary = std::array<double, num>;
+  using Base = update_tuple_sketch<std::vector<double>, std::vector<double>, array_of_doubles_update_policy<A>, A>;
+  using resize_factor = typename Base::resize_factor;
+
+  class builder;
+
+  compact_array_of_doubles_sketch<A> compact(bool ordered = true) const;
+  uint8_t get_num_values() const;
+
+private:
+  // for builder
+  update_array_of_doubles_sketch(uint8_t lg_cur_size, uint8_t lg_nom_size, resize_factor rf, uint64_t theta,
+      uint64_t seed, const array_of_doubles_update_policy<A>& policy, const A& allocator);
+};
+
+template<typename A>
+class update_array_of_doubles_sketch<A>::builder: public Base::builder {
+public:
+  builder(const array_of_doubles_update_policy<A>& policy = array_of_doubles_update_policy<A>(), const A& allocator = A());
+  update_array_of_doubles_sketch<A> build() const;
+};
+
+template<typename A = std::allocator<std::vector<double>>>
+class compact_array_of_doubles_sketch: public compact_tuple_sketch<std::vector<double>, A> {
+public:
+  using Summary = std::vector<double>;
   using Base = compact_tuple_sketch<Summary, A>;
   using Entry = typename Base::Entry;
   using AllocEntry = typename Base::AllocEntry;
@@ -57,14 +91,19 @@
   static const uint8_t SKETCH_TYPE = 3;
   enum flags { UNUSED1, UNUSED2, IS_EMPTY, HAS_ENTRIES, IS_ORDERED };
 
-  compact_array_of_doubles_sketch(const Base& other, bool ordered = true);
+  template<typename Sketch>
+  compact_array_of_doubles_sketch(const Sketch& other, bool ordered = true);
+
+  uint8_t get_num_values() const;
 
   void serialize(std::ostream& os) const;
 
   static compact_array_of_doubles_sketch deserialize(std::istream& is, uint64_t seed = DEFAULT_SEED, const A& allocator = A());
 
   // for internal use
-  compact_array_of_doubles_sketch(bool is_empty, bool is_ordered, uint16_t seed_hash, uint64_t theta, std::vector<Entry, AllocEntry>&& entries);
+  compact_array_of_doubles_sketch(bool is_empty, bool is_ordered, uint16_t seed_hash, uint64_t theta, std::vector<Entry, AllocEntry>&& entries, uint8_t num_values);
+private:
+  uint8_t num_values;
 };
 
 } /* namespace datasketches */
diff --git a/tuple/include/array_of_doubles_sketch_impl.hpp b/tuple/include/array_of_doubles_sketch_impl.hpp
index db0cac3..77e3b2b 100644
--- a/tuple/include/array_of_doubles_sketch_impl.hpp
+++ b/tuple/include/array_of_doubles_sketch_impl.hpp
@@ -19,93 +19,127 @@
 
 namespace datasketches {
 
-template<int num, typename A>
-compact_array_of_doubles_sketch<num, A>::compact_array_of_doubles_sketch(const Base& other, bool ordered):
-Base(other, ordered) {}
+template<typename A>
+update_array_of_doubles_sketch<A>::update_array_of_doubles_sketch(uint8_t lg_cur_size, uint8_t lg_nom_size, resize_factor rf,
+    uint64_t theta, uint64_t seed, const array_of_doubles_update_policy<A>& policy, const A& allocator):
+Base(lg_cur_size, lg_nom_size, rf, theta, seed, policy, allocator) {}
 
-template<int num, typename A>
-compact_array_of_doubles_sketch<num, A>::compact_array_of_doubles_sketch(bool is_empty, bool is_ordered, uint16_t seed_hash, uint64_t theta, std::vector<Entry, AllocEntry>&& entries):
-Base(is_empty, is_ordered, seed_hash, theta, std::move(entries)) {}
 
-template<int num, typename A>
-void compact_array_of_doubles_sketch<num, A>::serialize(std::ostream& os) const {
+template<typename A>
+uint8_t update_array_of_doubles_sketch<A>::get_num_values() const {
+  return this->policy_.get_num_values();
+}
+
+template<typename A>
+compact_array_of_doubles_sketch<A> update_array_of_doubles_sketch<A>::compact(bool ordered) const {
+  return compact_array_of_doubles_sketch<A>(*this, ordered);
+}
+
+// builder
+
+template<typename A>
+update_array_of_doubles_sketch<A>::builder::builder(const array_of_doubles_update_policy<A>& policy, const A& allocator):
+Base::builder(policy, allocator) {}
+
+template<typename A>
+update_array_of_doubles_sketch<A> update_array_of_doubles_sketch<A>::builder::build() const {
+  return update_array_of_doubles_sketch<A>(this->starting_lg_size(), this->lg_k_, this->rf_, this->starting_theta(), this->seed_, this->policy_, this->allocator_);
+}
+
+// compact sketch
+
+template<typename A>
+template<typename S>
+compact_array_of_doubles_sketch<A>::compact_array_of_doubles_sketch(const S& other, bool ordered):
+Base(other, ordered), num_values(other.get_num_values()) {}
+
+template<typename A>
+compact_array_of_doubles_sketch<A>::compact_array_of_doubles_sketch(bool is_empty, bool is_ordered,
+    uint16_t seed_hash, uint64_t theta, std::vector<Entry, AllocEntry>&& entries, uint8_t num_values):
+Base(is_empty, is_ordered, seed_hash, theta, std::move(entries)), num_values(num_values) {}
+
+template<typename A>
+uint8_t compact_array_of_doubles_sketch<A>::get_num_values() const {
+  return num_values;
+}
+
+template<typename A>
+void compact_array_of_doubles_sketch<A>::serialize(std::ostream& os) const {
   const uint8_t preamble_longs = 1;
-  os.write((char*)&preamble_longs, sizeof(preamble_longs));
+  os.write(reinterpret_cast<const char*>(&preamble_longs), sizeof(preamble_longs));
   const uint8_t serial_version = SERIAL_VERSION;
-  os.write((char*)&serial_version, sizeof(serial_version));
+  os.write(reinterpret_cast<const char*>(&serial_version), sizeof(serial_version));
   const uint8_t family = SKETCH_FAMILY;
-  os.write((char*)&family, sizeof(family));
+  os.write(reinterpret_cast<const char*>(&family), sizeof(family));
   const uint8_t type = SKETCH_TYPE;
-  os.write((char*)&type, sizeof(type));
+  os.write(reinterpret_cast<const char*>(&type), sizeof(type));
   const uint8_t flags_byte(
     (this->is_empty() ? 1 << flags::IS_EMPTY : 0) |
     (this->get_num_retained() > 0 ? 1 << flags::HAS_ENTRIES : 0) |
     (this->is_ordered() ? 1 << flags::IS_ORDERED : 0)
   );
-  os.write((char*)&flags_byte, sizeof(flags_byte));
-  const uint8_t num_values = num;
+  os.write(reinterpret_cast<const char*>(&flags_byte), sizeof(flags_byte));
   os.write(reinterpret_cast<const char*>(&num_values), sizeof(num_values));
   const uint16_t seed_hash = this->get_seed_hash();
-  os.write((char*)&seed_hash, sizeof(seed_hash));
-  os.write((char*)&(this->theta_), sizeof(uint64_t));
+  os.write(reinterpret_cast<const char*>(&seed_hash), sizeof(seed_hash));
+  os.write(reinterpret_cast<const char*>(&(this->theta_)), sizeof(uint64_t));
   if (this->get_num_retained() > 0) {
     const uint32_t num_entries = this->entries_.size();
-    os.write((char*)&num_entries, sizeof(num_entries));
+    os.write(reinterpret_cast<const char*>(&num_entries), sizeof(num_entries));
     const uint32_t unused32 = 0;
-    os.write((char*)&unused32, sizeof(unused32));
+    os.write(reinterpret_cast<const char*>(&unused32), sizeof(unused32));
     for (const auto& it: this->entries_) {
-      os.write((char*)&it.first, sizeof(uint64_t));
+      os.write(reinterpret_cast<const char*>(&it.first), sizeof(uint64_t));
     }
     for (const auto& it: this->entries_) {
-      os.write((char*)&it.second, sizeof(Summary));
+      os.write(reinterpret_cast<const char*>(it.second.data()), it.second.size() * sizeof(double));
     }
   }
 }
 
-template<int num, typename A>
-compact_array_of_doubles_sketch<num, A> compact_array_of_doubles_sketch<num, A>::deserialize(std::istream& is, uint64_t seed, const A& allocator) {
+template<typename A>
+compact_array_of_doubles_sketch<A> compact_array_of_doubles_sketch<A>::deserialize(std::istream& is, uint64_t seed, const A& allocator) {
   uint8_t preamble_longs;
-  is.read((char*)&preamble_longs, sizeof(preamble_longs));
+  is.read(reinterpret_cast<char*>(&preamble_longs), sizeof(preamble_longs));
   uint8_t serial_version;
-  is.read((char*)&serial_version, sizeof(serial_version));
+  is.read(reinterpret_cast<char*>(&serial_version), sizeof(serial_version));
   uint8_t family;
-  is.read((char*)&family, sizeof(family));
+  is.read(reinterpret_cast<char*>(&family), sizeof(family));
   uint8_t type;
-  is.read((char*)&type, sizeof(type));
+  is.read(reinterpret_cast<char*>(&type), sizeof(type));
   uint8_t flags_byte;
-  is.read((char*)&flags_byte, sizeof(flags_byte));
+  is.read(reinterpret_cast<char*>(&flags_byte), sizeof(flags_byte));
   uint8_t num_values;
-  is.read((char*)&num_values, sizeof(num_values));
+  is.read(reinterpret_cast<char*>(&num_values), sizeof(num_values));
   uint16_t seed_hash;
-  is.read((char*)&seed_hash, sizeof(seed_hash));
+  is.read(reinterpret_cast<char*>(&seed_hash), sizeof(seed_hash));
   checker<true>::check_sketch_family(family, SKETCH_FAMILY);
   checker<true>::check_sketch_type(type, SKETCH_TYPE);
   checker<true>::check_serial_version(serial_version, SERIAL_VERSION);
-  check_value(num_values, static_cast<uint8_t>(num), "number of values");
   const bool has_entries = flags_byte & (1 << flags::HAS_ENTRIES);
   if (has_entries) checker<true>::check_seed_hash(seed_hash, compute_seed_hash(seed));
 
   uint64_t theta;
-  is.read((char*)&theta, sizeof(theta));
+  is.read(reinterpret_cast<char*>(&theta), sizeof(theta));
   std::vector<Entry, AllocEntry> entries(allocator);
   uint32_t num_entries = 0;
   if (has_entries) {
-    is.read((char*)&num_entries, sizeof(num_entries));
+    is.read(reinterpret_cast<char*>(&num_entries), sizeof(num_entries));
     uint32_t unused32;
-    is.read((char*)&unused32, sizeof(unused32));
+    is.read(reinterpret_cast<char*>(&unused32), sizeof(unused32));
     entries.reserve(num_entries);
     std::vector<uint64_t, AllocU64> keys(num_entries, 0, allocator);
-    is.read((char*)keys.data(), num_entries * sizeof(uint64_t));
-    std::vector<Summary, A> summaries(num_entries, Summary(), allocator);
-    is.read((char*)summaries.data(), num_entries * sizeof(Summary));
+    is.read(reinterpret_cast<char*>(keys.data()), num_entries * sizeof(uint64_t));
     for (size_t i = 0; i < num_entries; ++i) {
-      entries.push_back(Entry(keys[i], summaries[i]));
+      Summary s(num_values, 0, allocator);
+      is.read(reinterpret_cast<char*>(s.data()), num_values * sizeof(double));
+      entries.push_back(Entry(keys[i], std::move(s)));
     }
   }
   if (!is.good()) throw std::runtime_error("error reading from std::istream");
   const bool is_empty = flags_byte & (1 << flags::IS_EMPTY);
   const bool is_ordered = flags_byte & (1 << flags::IS_ORDERED);
-  return compact_array_of_doubles_sketch(is_empty, is_ordered, seed_hash, theta, std::move(entries));
+  return compact_array_of_doubles_sketch(is_empty, is_ordered, seed_hash, theta, std::move(entries), num_values);
 }
 
 } /* namespace datasketches */
diff --git a/tuple/include/tuple_sketch.hpp b/tuple/include/tuple_sketch.hpp
index 915f170..7e2475a 100644
--- a/tuple/include/tuple_sketch.hpp
+++ b/tuple/include/tuple_sketch.hpp
@@ -325,7 +325,7 @@
   virtual const_iterator begin() const;
   virtual const_iterator end() const;
 
-private:
+protected:
   Policy policy_;
   tuple_map map_;
 
@@ -475,7 +475,7 @@
    */
   update_tuple_sketch<S, U, P, A> build() const;
 
-private:
+protected:
   P policy_;
   A allocator_;
 };
diff --git a/tuple/test/aod_2_compact_exact_from_java.sk b/tuple/test/aod_2_compact_exact_from_java.sk
new file mode 100644
index 0000000..a14fd08
--- /dev/null
+++ b/tuple/test/aod_2_compact_exact_from_java.sk
Binary files differ
diff --git a/tuple/test/aod_3_compact_empty_from_java.sk b/tuple/test/aod_3_compact_empty_from_java.sk
new file mode 100644
index 0000000..1579d9b
--- /dev/null
+++ b/tuple/test/aod_3_compact_empty_from_java.sk
@@ -0,0 +1 @@
+	̓ÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/tuple/test/array_of_doubles_sketch_test.cpp b/tuple/test/array_of_doubles_sketch_test.cpp
index f72861b..539962a 100644
--- a/tuple/test/array_of_doubles_sketch_test.cpp
+++ b/tuple/test/array_of_doubles_sketch_test.cpp
@@ -34,7 +34,7 @@
 #endif
 
 TEST_CASE("aod sketch: serialization compatibility with java - empty", "[tuple_sketch]") {
-  auto update_sketch = update_array_of_doubles_sketch<1>::builder().build();
+  auto update_sketch = update_array_of_doubles_sketch<>::builder().build();
   REQUIRE(update_sketch.is_empty());
   REQUIRE(update_sketch.get_num_retained() == 0);
   auto compact_sketch = update_sketch.compact();
@@ -43,7 +43,27 @@
   std::ifstream is;
   is.exceptions(std::ios::failbit | std::ios::badbit);
   is.open(inputPath + "aod_1_compact_empty_from_java.sk", std::ios::binary);
-  auto compact_sketch_from_java = compact_array_of_doubles_sketch<1>::deserialize(is);
+  auto compact_sketch_from_java = compact_array_of_doubles_sketch<>::deserialize(is);
+  REQUIRE(compact_sketch.get_num_retained() == compact_sketch_from_java.get_num_retained());
+  REQUIRE(compact_sketch.get_theta() == Approx(compact_sketch_from_java.get_theta()).margin(1e-10));
+  REQUIRE(compact_sketch.get_estimate() == Approx(compact_sketch_from_java.get_estimate()).margin(1e-10));
+  REQUIRE(compact_sketch.get_lower_bound(1) == Approx(compact_sketch_from_java.get_lower_bound(1)).margin(1e-10));
+  REQUIRE(compact_sketch.get_upper_bound(1) == Approx(compact_sketch_from_java.get_upper_bound(1)).margin(1e-10));
+}
+
+TEST_CASE("aod sketch: serialization compatibility with java - empty configured for three values", "[tuple_sketch]") {
+  auto update_sketch = update_array_of_doubles_sketch<>::builder(3).build();
+  REQUIRE(update_sketch.is_empty());
+  REQUIRE(update_sketch.get_num_retained() == 0);
+  REQUIRE(update_sketch.get_num_values() == 3);
+  auto compact_sketch = update_sketch.compact();
+
+  // read binary sketch from Java
+  std::ifstream is;
+  is.exceptions(std::ios::failbit | std::ios::badbit);
+  is.open(inputPath + "aod_3_compact_empty_from_java.sk", std::ios::binary);
+  auto compact_sketch_from_java = compact_array_of_doubles_sketch<>::deserialize(is);
+  REQUIRE(compact_sketch.get_num_values() == compact_sketch_from_java.get_num_values());
   REQUIRE(compact_sketch.get_num_retained() == compact_sketch_from_java.get_num_retained());
   REQUIRE(compact_sketch.get_theta() == Approx(compact_sketch_from_java.get_theta()).margin(1e-10));
   REQUIRE(compact_sketch.get_estimate() == Approx(compact_sketch_from_java.get_estimate()).margin(1e-10));
@@ -52,8 +72,8 @@
 }
 
 TEST_CASE("aod sketch: serialization compatibility with java - non-empty no entries", "[tuple_sketch]") {
-  auto update_sketch = update_array_of_doubles_sketch<1>::builder().set_p(0.01).build();
-  std::array<double, 1> a = {1};
+  auto update_sketch = update_array_of_doubles_sketch<>::builder().set_p(0.01).build();
+  std::vector<double> a = {1};
   update_sketch.update(1, a);
   REQUIRE_FALSE(update_sketch.is_empty());
   REQUIRE(update_sketch.get_num_retained() == 0);
@@ -63,7 +83,7 @@
   std::ifstream is;
   is.exceptions(std::ios::failbit | std::ios::badbit);
   is.open(inputPath + "aod_1_compact_non_empty_no_entries_from_java.sk", std::ios::binary);
-  auto compact_sketch_from_java = compact_array_of_doubles_sketch<1>::deserialize(is);
+  auto compact_sketch_from_java = compact_array_of_doubles_sketch<>::deserialize(is);
   REQUIRE(compact_sketch.get_num_retained() == compact_sketch_from_java.get_num_retained());
   REQUIRE(compact_sketch.get_theta() == Approx(compact_sketch_from_java.get_theta()).margin(1e-10));
   REQUIRE(compact_sketch.get_estimate() == Approx(compact_sketch_from_java.get_estimate()).margin(1e-10));
@@ -72,8 +92,8 @@
 }
 
 TEST_CASE("aod sketch: serialization compatibility with java - estimation mode", "[tuple_sketch]") {
-  auto update_sketch = update_array_of_doubles_sketch<1>::builder().build();
-  std::array<double, 1> a = {1};
+  auto update_sketch = update_array_of_doubles_sketch<>::builder().build();
+  std::vector<double> a = {1};
   for (int i = 0; i < 8192; ++i) update_sketch.update(i, a);
   auto compact_sketch = update_sketch.compact();
 
@@ -81,7 +101,7 @@
   std::ifstream is;
   is.exceptions(std::ios::failbit | std::ios::badbit);
   is.open(inputPath + "aod_1_compact_estimation_from_java.sk", std::ios::binary);
-  auto compact_sketch_from_java = compact_array_of_doubles_sketch<1>::deserialize(is);
+  auto compact_sketch_from_java = compact_array_of_doubles_sketch<>::deserialize(is);
   REQUIRE(compact_sketch.get_num_retained() == compact_sketch_from_java.get_num_retained());
   REQUIRE(compact_sketch.get_theta() == Approx(compact_sketch_from_java.get_theta()).margin(1e-10));
   REQUIRE(compact_sketch.get_estimate() == Approx(compact_sketch_from_java.get_estimate()).margin(1e-10));
@@ -94,7 +114,7 @@
 
   // sketch from Java is not ordered
   // transform it to ordered so that iteration sequence would match exactly
-  compact_array_of_doubles_sketch<1> ordered_sketch_from_java(compact_sketch_from_java, true);
+  compact_array_of_doubles_sketch<> ordered_sketch_from_java(compact_sketch_from_java, true);
   auto it = ordered_sketch_from_java.begin();
   for (const auto& entry: compact_sketch) {
     REQUIRE(entry == *it);
@@ -102,16 +122,51 @@
   }
 }
 
+TEST_CASE("aod sketch: serialization compatibility with java - exact mode with two values", "[tuple_sketch]") {
+  auto update_sketch = update_array_of_doubles_sketch<>::builder(2).build();
+  std::vector<double> a = {1, 2};
+  for (int i = 0; i < 1000; ++i) update_sketch.update(i, a);
+  auto compact_sketch = update_sketch.compact();
+  REQUIRE_FALSE(compact_sketch.is_estimation_mode());
+
+  // read binary sketch from Java
+  std::ifstream is;
+  is.exceptions(std::ios::failbit | std::ios::badbit);
+  is.open(inputPath + "aod_2_compact_exact_from_java.sk", std::ios::binary);
+  auto compact_sketch_from_java = compact_array_of_doubles_sketch<>::deserialize(is);
+  REQUIRE(compact_sketch.get_num_retained() == compact_sketch_from_java.get_num_retained());
+  REQUIRE(compact_sketch.get_theta() == Approx(compact_sketch_from_java.get_theta()).margin(1e-10));
+  REQUIRE(compact_sketch.get_estimate() == Approx(compact_sketch_from_java.get_estimate()).margin(1e-10));
+  REQUIRE(compact_sketch.get_lower_bound(1) == Approx(compact_sketch_from_java.get_lower_bound(1)).margin(1e-10));
+  REQUIRE(compact_sketch.get_upper_bound(1) == Approx(compact_sketch_from_java.get_upper_bound(1)).margin(1e-10));
+  REQUIRE(compact_sketch.get_lower_bound(2) == Approx(compact_sketch_from_java.get_lower_bound(2)).margin(1e-10));
+  REQUIRE(compact_sketch.get_upper_bound(2) == Approx(compact_sketch_from_java.get_upper_bound(2)).margin(1e-10));
+  REQUIRE(compact_sketch.get_lower_bound(3) == Approx(compact_sketch_from_java.get_lower_bound(3)).margin(1e-10));
+  REQUIRE(compact_sketch.get_upper_bound(3) == Approx(compact_sketch_from_java.get_upper_bound(3)).margin(1e-10));
+
+  // sketch from Java is not ordered
+  // transform it to ordered so that iteration sequence would match exactly
+  compact_array_of_doubles_sketch<> ordered_sketch_from_java(compact_sketch_from_java, true);
+  auto it = ordered_sketch_from_java.begin();
+  for (const auto& entry: compact_sketch) {
+    REQUIRE(entry.first == (*it).first);
+    REQUIRE(entry.second.size() == 2);
+    REQUIRE(entry.second[0] == (*it).second[0]);
+    REQUIRE(entry.second[1] == (*it).second[1]);
+    ++it;
+  }
+}
+
 TEST_CASE("aod sketch: serialize deserialize - estimation mode", "[tuple_sketch]") {
-  auto update_sketch = update_array_of_doubles_sketch<2>::builder().build();
-  std::array<double, 2> a = {1, 2};
+  auto update_sketch = update_array_of_doubles_sketch<>::builder(2).build();
+  std::vector<double> a = {1, 2};
   for (int i = 0; i < 8192; ++i) update_sketch.update(i, a);
-  compact_array_of_doubles_sketch<2> compact_sketch = update_sketch.compact();
+  auto compact_sketch = update_sketch.compact();
 
   std::stringstream ss;
   ss.exceptions(std::ios::failbit | std::ios::badbit);
   compact_sketch.serialize(ss);
-  auto deserialized_sketch = compact_array_of_doubles_sketch<2>::deserialize(ss);
+  auto deserialized_sketch = compact_array_of_doubles_sketch<>::deserialize(ss);
   REQUIRE(compact_sketch.get_num_retained() == deserialized_sketch.get_num_retained());
   REQUIRE(compact_sketch.get_theta() == Approx(deserialized_sketch.get_theta()).margin(1e-10));
   REQUIRE(compact_sketch.get_estimate() == Approx(deserialized_sketch.get_estimate()).margin(1e-10));
@@ -124,7 +179,10 @@
   // sketches must be ordered and the iteration sequence must match exactly
   auto it = deserialized_sketch.begin();
   for (const auto& entry: compact_sketch) {
-    REQUIRE(entry == *it);
+    REQUIRE(entry.first == (*it).first);
+    REQUIRE(entry.second.size() == 2);
+    REQUIRE(entry.second[0] == (*it).second[0]);
+    REQUIRE(entry.second[1] == (*it).second[1]);
     ++it;
   }
 }