This is an automated email from the ASF dual-hosted git repository.

leerho pushed a commit to branch Tuple_Theta_Extension
in repository 
https://gitbox.apache.org/repos/asf/incubator-datasketches-java.git


The following commit(s) were added to refs/heads/Tuple_Theta_Extension by this 
push:
     new cec94de  Multiple corrections to Intersection and to AnotB.
cec94de is described below

commit cec94de8bf8b1b6ca8b99d03a668204e27a66c97
Author: Lee Rhodes <[email protected]>
AuthorDate: Sat May 30 16:34:00 2020 -0700

    Multiple corrections to Intersection and to AnotB.
    
    Much improved unit tests.
---
 .../java/org/apache/datasketches/tuple/Filter.java |   2 +-
 .../apache/datasketches/tuple/Intersection.java    | 119 ++++----
 .../datasketches/tuple/QuickSelectSketch.java      |   5 +-
 .../apache/datasketches/tuple/UpdatableSketch.java |   2 +-
 .../tuple/CompactSketchWithDoubleSummaryTest.java  |   1 +
 .../org/apache/datasketches/tuple/MiscTest.java    |  53 ++++
 .../tuple/SerializerDeserializerTest.java          |  12 +-
 .../tuple/adouble/AdoubleAnotBTest.java            |   2 +
 .../tuple/adouble/AdoubleIntersectionTest.java     | 332 +++++++++++++++++++++
 ...WithDoubleSummaryTest.java => AdoubleTest.java} | 309 +------------------
 .../tuple/adouble/AdoubleUnionTest.java            | 161 ++++++++++
 11 files changed, 639 insertions(+), 359 deletions(-)

diff --git a/src/main/java/org/apache/datasketches/tuple/Filter.java 
b/src/main/java/org/apache/datasketches/tuple/Filter.java
index db975ae..5f7b096 100644
--- a/src/main/java/org/apache/datasketches/tuple/Filter.java
+++ b/src/main/java/org/apache/datasketches/tuple/Filter.java
@@ -65,7 +65,7 @@ public class Filter<T extends Summary> {
 
         sketch.setThetaLong(sketchIn.getThetaLong());
         if (!sketchIn.isEmpty()) {
-            sketch.setNotEmpty();
+            sketch.setEmpty(false);
         }
 
         return sketch.compact();
diff --git a/src/main/java/org/apache/datasketches/tuple/Intersection.java 
b/src/main/java/org/apache/datasketches/tuple/Intersection.java
index 0c32089..4fe6eb3 100644
--- a/src/main/java/org/apache/datasketches/tuple/Intersection.java
+++ b/src/main/java/org/apache/datasketches/tuple/Intersection.java
@@ -28,18 +28,18 @@ import org.apache.datasketches.SketchesStateException;
 
 /**
  * Computes an intersection of two or more generic tuple sketches.
- * A new instance represents the Universal Set.
- * Every update() computes an intersection with the internal set
- * and can only reduce the internal set.
+ * A new instance represents the Universal Set. Because the Universal Set
+ * cannot be realized a <i>getResult()</i> on a new instance will produce an 
error.
+ * Every update() computes an intersection with the internal state, which will 
never
+ * grow larger and may be reduced to zero.
  * @param <S> Type of Summary
  */
 public class Intersection<S extends Summary> {
-
   private final SummarySetOperations<S> summarySetOps_;
   private QuickSelectSketch<S> sketch_;
-  private boolean isEmpty_;
-  private long theta_;
-  private boolean isFirstCall_;
+  private boolean empty_;
+  private long thetaLong_;
+  private boolean firstCall_;
 
   /**
    * Creates new instance
@@ -47,59 +47,63 @@ public class Intersection<S extends Summary> {
    */
   public Intersection(final SummarySetOperations<S> summarySetOps) {
     summarySetOps_ = summarySetOps;
-    isEmpty_ = false; // universal set at the start
-    theta_ = Long.MAX_VALUE;
-    isFirstCall_ = true;
+    sketch_ = null;
+    empty_ = false; // universal set at the start
+    thetaLong_ = Long.MAX_VALUE;
+    firstCall_ = true;
   }
 
   /**
-   * Updates the internal set by intersecting it with the given sketch
-   * @param sketchIn input sketch to intersect with the internal set
+   * Updates the internal state by intersecting it with the given sketch
+   * @param sketchIn input sketch to intersect with the internal state
    */
   @SuppressWarnings({ "unchecked", "null" })
   public void update(final Sketch<S> sketchIn) {
-    final boolean isFirstCall = isFirstCall_;
-    isFirstCall_ = false;
+    final boolean firstCall = firstCall_;
+    firstCall_ = false;
     if (sketchIn == null) {
-      isEmpty_ = true;
+      empty_ = (thetaLong_ == Long.MAX_VALUE);
       sketch_ = null;
       return;
     }
-    theta_ = min(theta_, sketchIn.getThetaLong());
-    isEmpty_ |= sketchIn.isEmpty();
-    if (isEmpty_ || (sketchIn.getRetainedEntries() == 0)) {
+    thetaLong_ = min(thetaLong_, sketchIn.getThetaLong()); //Theta rule
+    empty_ |= sketchIn.isEmpty();                          //Empty rule
+    if (empty_ || (sketchIn.getRetainedEntries() == 0)) {
+      empty_ = (thetaLong_ == Long.MAX_VALUE);
       sketch_ = null;
       return;
     }
-    if (isFirstCall) {
+    if (firstCall) {
       sketch_ = new QuickSelectSketch<>(sketchIn.getRetainedEntries(), 
ResizeFactor.X1.lg(), null);
       final SketchIterator<S> it = sketchIn.iterator();
       while (it.next()) {
-        final S summary = (S)it.getSummary().copy();
-        sketch_.insert(it.getKey(), summary);
+        sketch_.insert(it.getKey(), (S)it.getSummary().copy());
       }
     } else {
       if (sketch_ == null) {
+        empty_ = (thetaLong_ == Long.MAX_VALUE);
         return;
       }
-      final int matchSize = min(sketch_.getRetainedEntries(), 
sketchIn.getRetainedEntries());
-      final long[] matchKeys = new long[matchSize];
+      final int maxMatchSize = min(sketch_.getRetainedEntries(), 
sketchIn.getRetainedEntries());
+      final long[] matchKeys = new long[maxMatchSize];
       S[] matchSummaries = null;
       int matchCount = 0;
       final SketchIterator<S> it = sketchIn.iterator();
       while (it.next()) {
         final long key = it.getKey();
-        final S summary = sketch_.find(key);
-        if (summary != null) { //key found
+        if (key >= thetaLong_) {
+          continue;
+        }
+        final S mySummary = sketch_.find(key);
+        if (mySummary != null) { //key found
           matchKeys[matchCount] = key;
           if (matchSummaries == null) {
-            matchSummaries = (S[]) Array.newInstance(summary.getClass(), 
matchSize);
+            matchSummaries = (S[]) Array.newInstance(mySummary.getClass(), 
maxMatchSize);
           }
-          matchSummaries[matchCount] = summarySetOps_.intersection(summary, 
it.getSummary());
+          matchSummaries[matchCount] = summarySetOps_.intersection(mySummary, 
it.getSummary());
           matchCount++;
         }
       }
-      sketch_ = null;
       if (matchCount > 0) { //therefore matchSummaries != null.
         // assumes that constructor of QuickSelectSketch bumps the requested 
size
         // up to the nearest power of 2
@@ -107,35 +111,38 @@ public class Intersection<S extends Summary> {
         for (int i = 0; i < matchCount; i++) {
           sketch_.insert(matchKeys[i], matchSummaries[i]);
         }
+        sketch_.setThetaLong(thetaLong_);
+        empty_ = (thetaLong_ == Long.MAX_VALUE) && 
(sketch_.getRetainedEntries() == 0);
+        sketch_.setEmpty(empty_);
+      } else {
+        sketch_ = null;
+        empty_ = (thetaLong_ == Long.MAX_VALUE);
       }
     }
-    if (sketch_ != null) {
-      sketch_.setThetaLong(theta_);
-      sketch_.setNotEmpty();
-    }
   }
 
   /**
    * Updates the internal set by intersecting it with the given Theta sketch
-   * @param sketchIn input Theta Sketch to intersect with the internal set
+   * @param sketchIn input Theta Sketch to intersect with the internal state.
    * @param summary the given proxy summary for the Theta Sketch, which 
doesn't have one.
    */
   @SuppressWarnings({ "unchecked", "null" })
   public void update(final org.apache.datasketches.theta.Sketch sketchIn, 
final S summary) {
-    final boolean isFirstCall = isFirstCall_;
-    isFirstCall_ = false;
+    final boolean firstCall = firstCall_;
+    firstCall_ = false;
     if (sketchIn == null) {
-      isEmpty_ = true;
+      empty_ = (thetaLong_ == Long.MAX_VALUE);
       sketch_ = null;
       return;
     }
-    theta_ = min(theta_, sketchIn.getThetaLong());
-    isEmpty_ |= sketchIn.isEmpty();
-    if (isEmpty_ || (sketchIn.getRetainedEntries() == 0)) {
+    thetaLong_ = min(thetaLong_, sketchIn.getThetaLong()); //Theta rule
+    empty_ |= sketchIn.isEmpty();                          //Empty rule
+    if (empty_ || (sketchIn.getRetainedEntries() == 0)) {
+      empty_ = (thetaLong_ == Long.MAX_VALUE);
       sketch_ = null;
       return;
     }
-    if (isFirstCall) {
+    if (firstCall) {
       sketch_ = new QuickSelectSketch<>(sketchIn.getRetainedEntries(), 
ResizeFactor.X1.lg(), null);
       final org.apache.datasketches.theta.HashIterator it = 
sketchIn.iterator();
       while (it.next()) {
@@ -143,26 +150,29 @@ public class Intersection<S extends Summary> {
       }
     } else {
       if (sketch_ == null) {
+        empty_ = (thetaLong_ == Long.MAX_VALUE);
         return;
       }
-      final int matchSize = min(sketch_.getRetainedEntries(), 
sketchIn.getRetainedEntries());
-      final long[] matchKeys = new long[matchSize];
+      final int maxMatchSize = min(sketch_.getRetainedEntries(), 
sketchIn.getRetainedEntries());
+      final long[] matchKeys = new long[maxMatchSize];
       S[] matchSummaries = null;
       int matchCount = 0;
       final org.apache.datasketches.theta.HashIterator it = 
sketchIn.iterator();
       while (it.next()) {
         final long key = it.get();
+        if (key >= thetaLong_) {
+          continue;
+        }
         final S mySummary = sketch_.find(key);
         if (mySummary != null) { //key found
           matchKeys[matchCount] = key;
           if (matchSummaries == null) {
-            matchSummaries = (S[]) Array.newInstance(mySummary.getClass(), 
matchSize);
+            matchSummaries = (S[]) Array.newInstance(mySummary.getClass(), 
maxMatchSize);
           }
           matchSummaries[matchCount] = summarySetOps_.intersection(mySummary, 
(S)summary.copy());
           matchCount++;
         }
       }
-      sketch_ = null;
       if (matchCount > 0) { //therefore matchSummaries != null.
         // assumes that constructor of QuickSelectSketch bumps the requested 
size
         // up to the nearest power of 2
@@ -170,26 +180,27 @@ public class Intersection<S extends Summary> {
         for (int i = 0; i < matchCount; i++) {
           sketch_.insert(matchKeys[i], matchSummaries[i]);
         }
+        sketch_.setThetaLong(thetaLong_);
+        empty_ = (thetaLong_ == Long.MAX_VALUE) && 
(sketch_.getRetainedEntries() == 0);
+        sketch_.setEmpty(empty_);
+      } else {
+        sketch_ = null;
+        empty_ = (thetaLong_ == Long.MAX_VALUE);
       }
     }
-    if (sketch_ != null) {
-      sketch_.setThetaLong(theta_);
-      sketch_.setNotEmpty();
-    }
   }
 
-
   /**
    * Gets the internal set as a CompactSketch
    * @return result of the intersections so far
    */
   public CompactSketch<S> getResult() {
-    if (isFirstCall_) {
+    if (firstCall_) {
       throw new SketchesStateException(
         "getResult() with no intervening intersections is not a legal 
result.");
     }
     if (sketch_ == null) {
-      return new CompactSketch<>(null, null, theta_, isEmpty_);
+      return new CompactSketch<>(null, null, thetaLong_, empty_);
     }
     return sketch_.compact();
   }
@@ -198,9 +209,9 @@ public class Intersection<S extends Summary> {
    * Resets the internal set to the initial state, which represents the 
Universal Set
    */
   public void reset() {
-    isEmpty_ = false;
-    theta_ = Long.MAX_VALUE;
+    empty_ = false;
+    thetaLong_ = Long.MAX_VALUE;
     sketch_ = null;
-    isFirstCall_ = true;
+    firstCall_ = true;
   }
 }
diff --git a/src/main/java/org/apache/datasketches/tuple/QuickSelectSketch.java 
b/src/main/java/org/apache/datasketches/tuple/QuickSelectSketch.java
index be41ed0..1fe0fb7 100644
--- a/src/main/java/org/apache/datasketches/tuple/QuickSelectSketch.java
+++ b/src/main/java/org/apache/datasketches/tuple/QuickSelectSketch.java
@@ -391,8 +391,8 @@ class QuickSelectSketch<S extends Summary> extends 
Sketch<S> {
     theta_ = theta;
   }
 
-  void setNotEmpty() {
-    isEmpty_ = false;
+  void setEmpty(final boolean value) {
+    isEmpty_ = value;
   }
 
   SummaryFactory<S> getSummaryFactory() {
@@ -434,6 +434,7 @@ class QuickSelectSketch<S extends Summary> extends 
Sketch<S> {
     final int index = HashOperations.hashInsertOnly(keys_, lgCurrentCapacity_, 
key);
     insertSummary(index, summary);
     count_++;
+    isEmpty_ = false;
   }
 
   private void updateTheta() {
diff --git a/src/main/java/org/apache/datasketches/tuple/UpdatableSketch.java 
b/src/main/java/org/apache/datasketches/tuple/UpdatableSketch.java
index 174e282..fd37888 100644
--- a/src/main/java/org/apache/datasketches/tuple/UpdatableSketch.java
+++ b/src/main/java/org/apache/datasketches/tuple/UpdatableSketch.java
@@ -141,7 +141,7 @@ public class UpdatableSketch<U, S extends 
UpdatableSummary<U>> extends QuickSele
   }
 
   private void insertOrIgnore(final long key, final U value) {
-    setNotEmpty();
+    setEmpty(false);
     if (key >= getThetaLong()) { return; }
     int index = findOrInsert(key);
     if (index < 0) {
diff --git 
a/src/test/java/org/apache/datasketches/tuple/CompactSketchWithDoubleSummaryTest.java
 
b/src/test/java/org/apache/datasketches/tuple/CompactSketchWithDoubleSummaryTest.java
index c1820f3..b068ea8 100644
--- 
a/src/test/java/org/apache/datasketches/tuple/CompactSketchWithDoubleSummaryTest.java
+++ 
b/src/test/java/org/apache/datasketches/tuple/CompactSketchWithDoubleSummaryTest.java
@@ -49,6 +49,7 @@ public class CompactSketchWithDoubleSummaryTest {
     SketchIterator<DoubleSummary> it = sketch.iterator();
     Assert.assertNotNull(it);
     Assert.assertFalse(it.next());
+    sketch.toString();
   }
 
   @Test
diff --git a/src/test/java/org/apache/datasketches/tuple/MiscTest.java 
b/src/test/java/org/apache/datasketches/tuple/MiscTest.java
new file mode 100644
index 0000000..1863930
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/tuple/MiscTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.tuple;
+
+import org.apache.datasketches.tuple.adouble.DoubleSummary;
+import org.apache.datasketches.tuple.adouble.DoubleSummary.Mode;
+import org.apache.datasketches.tuple.adouble.DoubleSummaryFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+@SuppressWarnings("javadoc")
+public class MiscTest {
+
+  @Test
+  public void checkUpdatableSketchBuilderReset() {
+    final DoubleSummary.Mode mode = Mode.Sum;
+    UpdatableSketchBuilder<Double, DoubleSummary> bldr =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode));
+    bldr.reset();
+  }
+
+  @Test
+  public void checkStringToByteArray() {
+    Util.stringToByteArray("");
+  }
+
+  @Test
+  public void checkDoubleToLongArray() {
+    final long[] v = Util.doubleToLongArray(-0.0);
+    Assert.assertEquals(v[0], 0);
+  }
+
+}
diff --git 
a/src/test/java/org/apache/datasketches/tuple/SerializerDeserializerTest.java 
b/src/test/java/org/apache/datasketches/tuple/SerializerDeserializerTest.java
index 61ab3fd..49863f2 100644
--- 
a/src/test/java/org/apache/datasketches/tuple/SerializerDeserializerTest.java
+++ 
b/src/test/java/org/apache/datasketches/tuple/SerializerDeserializerTest.java
@@ -19,12 +19,11 @@
 
 package org.apache.datasketches.tuple;
 
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.Family;
 import org.apache.datasketches.SketchesArgumentException;
+import org.apache.datasketches.memory.Memory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 @SuppressWarnings("javadoc")
 public class SerializerDeserializerTest {
@@ -58,4 +57,9 @@ public class SerializerDeserializerTest {
   public void validateFamilyWrongPreambleLength() {
     SerializerDeserializer.validateFamily((byte) Family.TUPLE.getID(), (byte) 
0);
   }
+
+  @Test(expectedExceptions = SketchesArgumentException.class)
+  public void checkBadSeedHash() {
+    org.apache.datasketches.tuple.Util.computeSeedHash(50541);
+  }
 }
diff --git 
a/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleAnotBTest.java 
b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleAnotBTest.java
index bd9d630..2490f5f 100644
--- a/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleAnotBTest.java
+++ b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleAnotBTest.java
@@ -64,6 +64,8 @@ public class AdoubleAnotBTest {
     //Stateful w B = Theta
     aNotB.setA(sketchA);
     aNotB.notB(skThetaB);
+    result = aNotB.getResult(false);
+    results.check(result);
     result = aNotB.getResult(true);
     results.check(result);
   }
diff --git 
a/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleIntersectionTest.java
 
b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleIntersectionTest.java
new file mode 100644
index 0000000..7f8662a
--- /dev/null
+++ 
b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleIntersectionTest.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.tuple.adouble;
+
+import static org.testng.Assert.fail;
+
+import org.apache.datasketches.SketchesStateException;
+import org.apache.datasketches.theta.UpdateSketch;
+import org.apache.datasketches.theta.UpdateSketchBuilder;
+import org.apache.datasketches.tuple.CompactSketch;
+import org.apache.datasketches.tuple.Intersection;
+import org.apache.datasketches.tuple.Sketch;
+import org.apache.datasketches.tuple.SketchIterator;
+import org.apache.datasketches.tuple.Sketches;
+import org.apache.datasketches.tuple.UpdatableSketch;
+import org.apache.datasketches.tuple.UpdatableSketchBuilder;
+import org.apache.datasketches.tuple.adouble.DoubleSummary.Mode;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+@SuppressWarnings("javadoc")
+public class AdoubleIntersectionTest {
+  private final DoubleSummary.Mode mode = Mode.Sum;
+
+  @Test
+  public void intersectionNotEmptyNoEntries() {
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>
+          (new 
DoubleSummaryFactory(mode)).setSamplingProbability(0.01f).build();
+    sketch1.update("a", 1.0); // this happens to get rejected because of 
sampling with low probability
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    intersection.update(sketch1);
+    CompactSketch<DoubleSummary> result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertFalse(result.isEmpty());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0, 0.0001);
+    Assert.assertTrue(result.getUpperBound(1) > 0);
+  }
+
+  @Test
+  public void intersectionExactWithNull() {
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    sketch1.update(1, 1.0);
+    sketch1.update(2, 1.0);
+    sketch1.update(3, 1.0);
+
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    intersection.update(sketch1);
+    intersection.update(null);
+    CompactSketch<DoubleSummary> result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertTrue(result.isEmpty());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0);
+    Assert.assertEquals(result.getUpperBound(1), 0.0);
+  }
+
+  @Test
+  public void intersectionExactWithEmpty() {
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    sketch1.update(1, 1.0);
+    sketch1.update(2, 1.0);
+    sketch1.update(3, 1.0);
+
+    Sketch<DoubleSummary> sketch2 = Sketches.createEmptySketch();
+
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    intersection.update(sketch1);
+    intersection.update(sketch2);
+    CompactSketch<DoubleSummary> result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertTrue(result.isEmpty());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0);
+    Assert.assertEquals(result.getUpperBound(1), 0.0);
+  }
+
+  @Test
+  public void intersectionExactMode() {
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    sketch1.update(1, 1.0);
+    sketch1.update(1, 1.0);
+    sketch1.update(2, 1.0);
+    sketch1.update(2, 1.0);
+
+    UpdatableSketch<Double, DoubleSummary> sketch2 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    sketch2.update(2, 1.0);
+    sketch2.update(2, 1.0);
+    sketch2.update(3, 1.0);
+    sketch2.update(3, 1.0);
+
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    intersection.update(sketch1);
+    intersection.update(sketch2);
+    CompactSketch<DoubleSummary> result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 1);
+    Assert.assertFalse(result.isEmpty());
+    Assert.assertEquals(result.getEstimate(), 1.0);
+    Assert.assertEquals(result.getLowerBound(1), 1.0);
+    Assert.assertEquals(result.getUpperBound(1), 1.0);
+    SketchIterator<DoubleSummary> it = result.iterator();
+    Assert.assertTrue(it.next());
+    Assert.assertEquals(it.getSummary().getValue(), 4.0);
+    Assert.assertFalse(it.next());
+
+    intersection.reset();
+    intersection.update(null);
+    result = intersection.getResult();
+    Assert.assertTrue(result.isEmpty());
+    Assert.assertFalse(result.isEstimationMode());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getUpperBound(1), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0);
+    Assert.assertEquals(result.getTheta(), 1.0);
+}
+
+  @Test
+  public void intersectionDisjointEstimationMode() {
+    int key = 0;
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    for (int i = 0; i < 8192; i++) {
+      sketch1.update(key++, 1.0);
+    }
+
+    UpdatableSketch<Double, DoubleSummary> sketch2 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    for (int i = 0; i < 8192; i++) {
+      sketch2.update(key++, 1.0);
+    }
+
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    intersection.update(sketch1);
+    intersection.update(sketch2);
+    CompactSketch<DoubleSummary> result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertFalse(result.isEmpty());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0);
+    Assert.assertTrue(result.getUpperBound(1) > 0);
+
+    // an intersection with no entries must survive more updates
+    intersection.update(sketch1);
+    result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertFalse(result.isEmpty());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0);
+    Assert.assertTrue(result.getUpperBound(1) > 0);
+  }
+
+  @Test
+  public void intersectionEstimationMode() {
+    int key = 0;
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    for (int i = 0; i < 8192; i++) {
+      sketch1.update(key++, 1.0);
+    }
+
+    key -= 4096; // overlap half of the entries
+    UpdatableSketch<Double, DoubleSummary> sketch2 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    for (int i = 0; i < 8192; i++) {
+      sketch2.update(key++, 1.0);
+    }
+
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    intersection.update(sketch1);
+    intersection.update(sketch2);
+    CompactSketch<DoubleSummary> result = intersection.getResult();
+    Assert.assertFalse(result.isEmpty());
+    // crude estimate of RSE(95%) = 2 / sqrt(result.getRetainedEntries())
+    Assert.assertEquals(result.getEstimate(), 4096.0, 4096 * 0.03);
+    Assert.assertTrue(result.getLowerBound(1) <= result.getEstimate());
+    Assert.assertTrue(result.getUpperBound(1) > result.getEstimate());
+    SketchIterator<DoubleSummary> it = result.iterator();
+    while (it.next()) {
+      Assert.assertEquals(it.getSummary().getValue(), 2.0);
+    }
+  }
+
+  @Test
+  public void checkExactIntersectionWithTheta() {
+    UpdateSketch thSkNull = null;
+    UpdateSketch thSkEmpty = new UpdateSketchBuilder().build();
+    UpdateSketch thSk10 = new UpdateSketchBuilder().build();
+    UpdateSketch thSk15 = new UpdateSketchBuilder().build();
+    for (int i = 0; i < 10; i++) { thSk10.update(i); }
+    for (int i = 0; i < 10; i++) { thSk15.update(i + 5); } //overlap = 5
+
+    DoubleSummary dsum = new DoubleSummaryFactory(mode).newSummary();
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    CompactSketch<DoubleSummary> result;
+
+    try { intersection.getResult(); fail(); }
+    catch (SketchesStateException e ) { } //OK.
+
+    intersection.update(thSkNull, dsum);
+    result = intersection.getResult();
+    Assert.assertTrue(result.isEmpty()); //Empty after null first call
+    intersection.reset();
+
+    intersection.update(thSkEmpty, dsum);
+    result = intersection.getResult();
+    Assert.assertTrue(result.isEmpty()); //Empty after empty first call
+    intersection.reset();
+
+    intersection.update(thSk10, dsum);
+    result = intersection.getResult();
+    Assert.assertEquals(result.getEstimate(), 10.0); //Returns valid first call
+    intersection.reset();
+
+    intersection.update(thSk10, dsum);  // Valid first call
+    intersection.update(thSkNull, dsum);
+    result = intersection.getResult();
+    Assert.assertTrue(result.isEmpty()); //Returns Empty after null second call
+    intersection.reset();
+
+    intersection.update(thSk10, dsum);  // Valid first call
+    intersection.update(thSkEmpty, dsum);
+    result = intersection.getResult();
+    Assert.assertTrue(result.isEmpty()); //Returns Empty after empty second 
call
+    intersection.reset();
+
+    intersection.update(thSk10, dsum);
+    intersection.update(thSk15, dsum);
+    result = intersection.getResult();
+    Assert.assertEquals(result.getEstimate(), 5.0); //Returns intersection
+    intersection.reset();
+  }
+
+  @Test
+  public void checkExactIntersectionWithThetaDisjoint() {
+    UpdateSketch thSkA = new 
UpdateSketchBuilder().setLogNominalEntries(10).build();
+    UpdateSketch thSkB = new 
UpdateSketchBuilder().setLogNominalEntries(10).build();
+    int key = 0;
+    for (int i = 0; i < 32;  i++) { thSkA.update(key++); }
+    for (int i = 0; i < 32; i++) { thSkB.update(key++); }
+
+    DoubleSummary dsum = new DoubleSummaryFactory(mode).newSummary();
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    CompactSketch<DoubleSummary> result;
+
+    intersection.update(thSkA, dsum);
+    intersection.update(thSkB, dsum);
+    result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+
+    // an intersection with no entries must survive more updates
+    intersection.update(thSkA, dsum);
+    result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    intersection.reset();
+  }
+
+  @Test
+  public void checkEstimatingIntersectionWithThetaOverlapping() {
+    UpdateSketch thSkA = new 
UpdateSketchBuilder().setLogNominalEntries(4).build();
+    UpdateSketch thSkB = new 
UpdateSketchBuilder().setLogNominalEntries(10).build();
+    for (int i = 0; i < 64;  i++) { thSkA.update(i); } //dense mode, low theta
+    for (int i = 32; i < 96; i++) { thSkB.update(i); } //exact overlapping
+
+    DoubleSummary dsum = new DoubleSummaryFactory(mode).newSummary();
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    CompactSketch<DoubleSummary> result;
+
+    intersection.update(thSkA, dsum);
+    intersection.update(thSkB, dsum);
+    result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 14);
+
+    thSkB.reset();
+    for (int i = 100; i < 164; i++) { thSkB.update(i); } //exact, disjoint
+    intersection.update(thSkB, dsum); //remove existing entries
+    result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    intersection.update(thSkB, dsum);
+    result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+  }
+
+  @Test
+  public void intersectionEmpty() {
+    UpdatableSketch<Double, DoubleSummary> sketch =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    Intersection<DoubleSummary> intersection =
+        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
+    intersection.update(sketch);
+    CompactSketch<DoubleSummary> result = intersection.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertTrue(result.isEmpty());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0);
+    Assert.assertEquals(result.getUpperBound(1), 0.0);
+  }
+
+}
diff --git 
a/src/test/java/org/apache/datasketches/tuple/adouble/UpdatableSketchWithDoubleSummaryTest.java
 b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleTest.java
similarity index 54%
rename from 
src/test/java/org/apache/datasketches/tuple/adouble/UpdatableSketchWithDoubleSummaryTest.java
rename to src/test/java/org/apache/datasketches/tuple/adouble/AdoubleTest.java
index e60a19f..882707f 100644
--- 
a/src/test/java/org/apache/datasketches/tuple/adouble/UpdatableSketchWithDoubleSummaryTest.java
+++ b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleTest.java
@@ -24,12 +24,9 @@ import static org.testng.Assert.assertEquals;
 import org.apache.datasketches.ResizeFactor;
 import org.apache.datasketches.SketchesArgumentException;
 import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.tuple.CompactSketch;
-import org.apache.datasketches.tuple.Intersection;
 import org.apache.datasketches.tuple.Sketch;
 import org.apache.datasketches.tuple.SketchIterator;
 import org.apache.datasketches.tuple.Sketches;
-import org.apache.datasketches.tuple.Union;
 import org.apache.datasketches.tuple.UpdatableSketch;
 import org.apache.datasketches.tuple.UpdatableSketchBuilder;
 import org.apache.datasketches.tuple.adouble.DoubleSummary.Mode;
@@ -37,7 +34,7 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 @SuppressWarnings("javadoc")
-public class UpdatableSketchWithDoubleSummaryTest {
+public class AdoubleTest {
   private final DoubleSummary.Mode mode = Mode.Sum;
 
   @Test
@@ -395,299 +392,17 @@ public class UpdatableSketchWithDoubleSummaryTest {
   }
 
   @Test
-  public void unionEmptySampling() {
-    UpdatableSketch<Double, DoubleSummary> sketch =
-        new UpdatableSketchBuilder<>(new 
DoubleSummaryFactory(mode)).setSamplingProbability(0.01f).build();
-    sketch.update(1, 1.0);
-    Assert.assertEquals(sketch.getRetainedEntries(), 0); // not retained due 
to low sampling probability
-
-    Union<DoubleSummary> union = new Union<>(new 
DoubleSummarySetOperations(mode, mode));
-    union.update(sketch);
-    CompactSketch<DoubleSummary> result = union.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertFalse(result.isEmpty());
-    Assert.assertTrue(result.isEstimationMode());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-  }
-
-  @Test
-  public void unionExactMode() {
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    sketch1.update(1, 1.0);
-    sketch1.update(1, 1.0);
-    sketch1.update(1, 1.0);
-    sketch1.update(2, 1.0);
-
-    UpdatableSketch<Double, DoubleSummary> sketch2 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    sketch2.update(2, 1.0);
-    sketch2.update(2, 1.0);
-    sketch2.update(3, 1.0);
-    sketch2.update(3, 1.0);
-    sketch2.update(3, 1.0);
-
-    Union<DoubleSummary> union = new Union<>(new 
DoubleSummarySetOperations(mode, mode));
-    union.update(sketch1);
-    union.update(sketch2);
-    CompactSketch<DoubleSummary> result = union.getResult();
-    Assert.assertEquals(result.getEstimate(), 3.0);
-
-    SketchIterator<DoubleSummary> it = result.iterator();
-    Assert.assertTrue(it.next());
-    Assert.assertEquals(it.getSummary().getValue(), 3.0);
-    Assert.assertTrue(it.next());
-    Assert.assertEquals(it.getSummary().getValue(), 3.0);
-    Assert.assertTrue(it.next());
-    Assert.assertEquals(it.getSummary().getValue(), 3.0);
-    Assert.assertFalse(it.next());
-
-    union.reset();
-    result = union.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertTrue(result.isEmpty());
-    Assert.assertFalse(result.isEstimationMode());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0);
-    Assert.assertEquals(result.getUpperBound(1), 0.0);
-    Assert.assertEquals(result.getTheta(), 1.0);
-  }
-
-  @Test
-  public void unionEstimationMode() {
-    int key = 0;
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    for (int i = 0; i < 8192; i++) {
-      sketch1.update(key++, 1.0);
-    }
-
-    key -= 4096; // overlap half of the entries
-    UpdatableSketch<Double, DoubleSummary> sketch2 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    for (int i = 0; i < 8192; i++) {
-      sketch2.update(key++, 1.0);
-    }
-
-    Union<DoubleSummary> union = new Union<>(4096, new 
DoubleSummarySetOperations(mode, mode));
-    union.update(sketch1);
-    union.update(sketch2);
-    CompactSketch<DoubleSummary> result = union.getResult();
-    Assert.assertEquals(result.getEstimate(), 12288.0, 12288 * 0.01);
-    Assert.assertTrue(result.getLowerBound(1) <= result.getEstimate());
-    Assert.assertTrue(result.getUpperBound(1) > result.getEstimate());
-  }
-
-  @Test
-  public void unionMixedMode() {
-    int key = 0;
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    for (int i = 0; i < 1000; i++) {
-      sketch1.update(key++, 1.0);
-      //System.out.println("theta1=" + sketch1.getTheta() + " " + 
sketch1.getThetaLong());
-    }
-
-    key -= 500; // overlap half of the entries
-    UpdatableSketch<Double, DoubleSummary> sketch2 =
-        new UpdatableSketchBuilder<>
-          (new 
DoubleSummaryFactory(mode)).setSamplingProbability(0.2f).build();
-    for (int i = 0; i < 20000; i++) {
-      sketch2.update(key++, 1.0);
-      //System.out.println("theta2=" + sketch2.getTheta() + " " + 
sketch2.getThetaLong());
-    }
-
-    Union<DoubleSummary> union = new Union<>(4096, new 
DoubleSummarySetOperations(mode, mode));
-    union.update(sketch1);
-    union.update(sketch2);
-    CompactSketch<DoubleSummary> result = union.getResult();
-    Assert.assertEquals(result.getEstimate(), 20500.0, 20500 * 0.01);
-    Assert.assertTrue(result.getLowerBound(1) <= result.getEstimate());
-    Assert.assertTrue(result.getUpperBound(1) > result.getEstimate());
-  }
-
-  @Test
-  public void intersectionEmpty() {
-    UpdatableSketch<Double, DoubleSummary> sketch =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    Intersection<DoubleSummary> intersection =
-        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
-    intersection.update(sketch);
-    CompactSketch<DoubleSummary> result = intersection.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertTrue(result.isEmpty());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0);
-    Assert.assertEquals(result.getUpperBound(1), 0.0);
-  }
-
-  @Test
-  public void intersectionNotEmptyNoEntries() {
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>
-          (new 
DoubleSummaryFactory(mode)).setSamplingProbability(0.01f).build();
-    sketch1.update("a", 1.0); // this happens to get rejected because of 
sampling with low probability
-    Intersection<DoubleSummary> intersection =
-        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
-    intersection.update(sketch1);
-    CompactSketch<DoubleSummary> result = intersection.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertFalse(result.isEmpty());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0, 0.0001);
-    Assert.assertTrue(result.getUpperBound(1) > 0);
-  }
-
-  @Test
-  public void intersectionExactWithNull() {
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    sketch1.update(1, 1.0);
-    sketch1.update(2, 1.0);
-    sketch1.update(3, 1.0);
-
-    Intersection<DoubleSummary> intersection =
-        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
-    intersection.update(sketch1);
-    intersection.update(null);
-    CompactSketch<DoubleSummary> result = intersection.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertTrue(result.isEmpty());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0);
-    Assert.assertEquals(result.getUpperBound(1), 0.0);
-  }
-
-  @Test
-  public void intersectionExactWithEmpty() {
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    sketch1.update(1, 1.0);
-    sketch1.update(2, 1.0);
-    sketch1.update(3, 1.0);
-
-    Sketch<DoubleSummary> sketch2 = Sketches.createEmptySketch();
-
-    Intersection<DoubleSummary> intersection =
-        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
-    intersection.update(sketch1);
-    intersection.update(sketch2);
-    CompactSketch<DoubleSummary> result = intersection.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertTrue(result.isEmpty());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0);
-    Assert.assertEquals(result.getUpperBound(1), 0.0);
-  }
-
-  @Test
-  public void intersectionExactMode() {
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    sketch1.update(1, 1.0);
-    sketch1.update(1, 1.0);
-    sketch1.update(2, 1.0);
-    sketch1.update(2, 1.0);
-
-    UpdatableSketch<Double, DoubleSummary> sketch2 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    sketch2.update(2, 1.0);
-    sketch2.update(2, 1.0);
-    sketch2.update(3, 1.0);
-    sketch2.update(3, 1.0);
-
-    Intersection<DoubleSummary> intersection =
-        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
-    intersection.update(sketch1);
-    intersection.update(sketch2);
-    CompactSketch<DoubleSummary> result = intersection.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 1);
-    Assert.assertFalse(result.isEmpty());
-    Assert.assertEquals(result.getEstimate(), 1.0);
-    Assert.assertEquals(result.getLowerBound(1), 1.0);
-    Assert.assertEquals(result.getUpperBound(1), 1.0);
-    SketchIterator<DoubleSummary> it = result.iterator();
-    Assert.assertTrue(it.next());
-    Assert.assertEquals(it.getSummary().getValue(), 4.0);
-    Assert.assertFalse(it.next());
-
-    intersection.reset();
-    intersection.update(null);
-    result = intersection.getResult();
-    Assert.assertTrue(result.isEmpty());
-    Assert.assertFalse(result.isEstimationMode());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getUpperBound(1), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0);
-    Assert.assertEquals(result.getTheta(), 1.0);
-}
-
-  @Test
-  public void intersectionDisjointEstimationMode() {
-    int key = 0;
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    for (int i = 0; i < 8192; i++) {
-      sketch1.update(key++, 1.0);
-    }
-
-    UpdatableSketch<Double, DoubleSummary> sketch2 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    for (int i = 0; i < 8192; i++) {
-      sketch2.update(key++, 1.0);
-    }
-
-    Intersection<DoubleSummary> intersection =
-        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
-    intersection.update(sketch1);
-    intersection.update(sketch2);
-    CompactSketch<DoubleSummary> result = intersection.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertFalse(result.isEmpty());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0);
-    Assert.assertTrue(result.getUpperBound(1) > 0);
-
-    // an intersection with no entries must survive more updates
-    intersection.update(sketch1);
-    result = intersection.getResult();
-    Assert.assertEquals(result.getRetainedEntries(), 0);
-    Assert.assertFalse(result.isEmpty());
-    Assert.assertEquals(result.getEstimate(), 0.0);
-    Assert.assertEquals(result.getLowerBound(1), 0.0);
-    Assert.assertTrue(result.getUpperBound(1) > 0);
-  }
-
-  @Test
-  public void intersectionEstimationMode() {
-    int key = 0;
-    UpdatableSketch<Double, DoubleSummary> sketch1 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    for (int i = 0; i < 8192; i++) {
-      sketch1.update(key++, 1.0);
-    }
-
-    key -= 4096; // overlap half of the entries
-    UpdatableSketch<Double, DoubleSummary> sketch2 =
-        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
-    for (int i = 0; i < 8192; i++) {
-      sketch2.update(key++, 1.0);
-    }
-
-    Intersection<DoubleSummary> intersection =
-        new Intersection<>(new DoubleSummarySetOperations(mode, mode));
-    intersection.update(sketch1);
-    intersection.update(sketch2);
-    CompactSketch<DoubleSummary> result = intersection.getResult();
-    Assert.assertFalse(result.isEmpty());
- // crude estimate of RSE(95%) = 2 / sqrt(result.getRetainedEntries())
-    Assert.assertEquals(result.getEstimate(), 4096.0, 4096 * 0.03);
-    Assert.assertTrue(result.getLowerBound(1) <= result.getEstimate());
-    Assert.assertTrue(result.getUpperBound(1) > result.getEstimate());
-    SketchIterator<DoubleSummary> it = result.iterator();
-    while (it.next()) {
-      Assert.assertEquals(it.getSummary().getValue(), 2.0);
-    }
+  public void checkUpdatableSketch() {
+    DoubleSummaryFactory dsumFact = new DoubleSummaryFactory(mode);
+    //DoubleSummary dsum = dsumFact.newSummary();
+    UpdatableSketchBuilder<Double, DoubleSummary> bldr = new 
UpdatableSketchBuilder<>(dsumFact);
+    UpdatableSketch<Double, DoubleSummary> usk = bldr.build();
+    final byte[] byteArr = new byte[0];
+    usk.update(byteArr, new Double(0));
+    final int[] intArr = new int[0];
+    usk.update(intArr, new Double(1));
+    final long[] longArr = new long[0];
+    usk.update(longArr, new Double(2));
   }
 
   @Test(expectedExceptions = SketchesArgumentException.class)
diff --git 
a/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleUnionTest.java 
b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleUnionTest.java
new file mode 100644
index 0000000..2ef2485
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/tuple/adouble/AdoubleUnionTest.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.tuple.adouble;
+
+import org.apache.datasketches.theta.UpdateSketch;
+import org.apache.datasketches.theta.UpdateSketchBuilder;
+import org.apache.datasketches.tuple.CompactSketch;
+import org.apache.datasketches.tuple.SketchIterator;
+import org.apache.datasketches.tuple.Union;
+import org.apache.datasketches.tuple.UpdatableSketch;
+import org.apache.datasketches.tuple.UpdatableSketchBuilder;
+import org.apache.datasketches.tuple.adouble.DoubleSummary.Mode;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+@SuppressWarnings("javadoc")
+public class AdoubleUnionTest {
+  private final DoubleSummary.Mode mode = Mode.Sum;
+
+  @Test
+  public void unionEmptySampling() {
+    UpdatableSketch<Double, DoubleSummary> sketch =
+        new UpdatableSketchBuilder<>(new 
DoubleSummaryFactory(mode)).setSamplingProbability(0.01f).build();
+    sketch.update(1, 1.0);
+    Assert.assertEquals(sketch.getRetainedEntries(), 0); // not retained due 
to low sampling probability
+
+    Union<DoubleSummary> union = new Union<>(new 
DoubleSummarySetOperations(mode, mode));
+    union.update(sketch);
+    CompactSketch<DoubleSummary> result = union.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertFalse(result.isEmpty());
+    Assert.assertTrue(result.isEstimationMode());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+  }
+
+  @Test
+  public void unionExactMode() {
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    sketch1.update(1, 1.0);
+    sketch1.update(1, 1.0);
+    sketch1.update(1, 1.0);
+    sketch1.update(2, 1.0);
+
+    UpdatableSketch<Double, DoubleSummary> sketch2 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    sketch2.update(2, 1.0);
+    sketch2.update(2, 1.0);
+    sketch2.update(3, 1.0);
+    sketch2.update(3, 1.0);
+    sketch2.update(3, 1.0);
+
+    Union<DoubleSummary> union = new Union<>(new 
DoubleSummarySetOperations(mode, mode));
+    union.update(sketch1);
+    union.update(sketch2);
+    CompactSketch<DoubleSummary> result = union.getResult();
+    Assert.assertEquals(result.getEstimate(), 3.0);
+
+    SketchIterator<DoubleSummary> it = result.iterator();
+    Assert.assertTrue(it.next());
+    Assert.assertEquals(it.getSummary().getValue(), 3.0);
+    Assert.assertTrue(it.next());
+    Assert.assertEquals(it.getSummary().getValue(), 3.0);
+    Assert.assertTrue(it.next());
+    Assert.assertEquals(it.getSummary().getValue(), 3.0);
+    Assert.assertFalse(it.next());
+
+    union.reset();
+    result = union.getResult();
+    Assert.assertEquals(result.getRetainedEntries(), 0);
+    Assert.assertTrue(result.isEmpty());
+    Assert.assertFalse(result.isEstimationMode());
+    Assert.assertEquals(result.getEstimate(), 0.0);
+    Assert.assertEquals(result.getLowerBound(1), 0.0);
+    Assert.assertEquals(result.getUpperBound(1), 0.0);
+    Assert.assertEquals(result.getTheta(), 1.0);
+  }
+
+  @Test
+  public void unionEstimationMode() {
+    int key = 0;
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    for (int i = 0; i < 8192; i++) {
+      sketch1.update(key++, 1.0);
+    }
+
+    key -= 4096; // overlap half of the entries
+    UpdatableSketch<Double, DoubleSummary> sketch2 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    for (int i = 0; i < 8192; i++) {
+      sketch2.update(key++, 1.0);
+    }
+
+    Union<DoubleSummary> union = new Union<>(4096, new 
DoubleSummarySetOperations(mode, mode));
+    union.update(sketch1);
+    union.update(sketch2);
+    CompactSketch<DoubleSummary> result = union.getResult();
+    Assert.assertEquals(result.getEstimate(), 12288.0, 12288 * 0.01);
+    Assert.assertTrue(result.getLowerBound(1) <= result.getEstimate());
+    Assert.assertTrue(result.getUpperBound(1) > result.getEstimate());
+  }
+
+  @Test
+  public void unionMixedMode() {
+    int key = 0;
+    UpdatableSketch<Double, DoubleSummary> sketch1 =
+        new UpdatableSketchBuilder<>(new DoubleSummaryFactory(mode)).build();
+    for (int i = 0; i < 1000; i++) {
+      sketch1.update(key++, 1.0);
+      //System.out.println("theta1=" + sketch1.getTheta() + " " + 
sketch1.getThetaLong());
+    }
+
+    key -= 500; // overlap half of the entries
+    UpdatableSketch<Double, DoubleSummary> sketch2 =
+        new UpdatableSketchBuilder<>
+          (new 
DoubleSummaryFactory(mode)).setSamplingProbability(0.2f).build();
+    for (int i = 0; i < 20000; i++) {
+      sketch2.update(key++, 1.0);
+      //System.out.println("theta2=" + sketch2.getTheta() + " " + 
sketch2.getThetaLong());
+    }
+
+    Union<DoubleSummary> union = new Union<>(4096, new 
DoubleSummarySetOperations(mode, mode));
+    union.update(sketch1);
+    union.update(sketch2);
+    CompactSketch<DoubleSummary> result = union.getResult();
+    Assert.assertEquals(result.getEstimate(), 20500.0, 20500 * 0.01);
+    Assert.assertTrue(result.getLowerBound(1) <= result.getEstimate());
+    Assert.assertTrue(result.getUpperBound(1) > result.getEstimate());
+  }
+
+  @Test
+  public void checkUnionUpdate() {
+    Union<DoubleSummary> union = new Union<>(new 
DoubleSummarySetOperations(mode, mode));
+    DoubleSummary dsum = new DoubleSummaryFactory(mode).newSummary();
+    UpdateSketch usk = new UpdateSketchBuilder().build();
+    for (int i = 0; i < 10; i++) { usk.update(i); }
+    union.update(usk, dsum);
+  }
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to