You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datasketches.apache.org by le...@apache.org on 2024/01/08 01:24:45 UTC

(datasketches-characterization) branch master updated: Bringing Kll test profiles up to date.

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 2028e49  Bringing Kll test profiles up to date.
2028e49 is described below

commit 2028e492749af14d35a0ff436a10f60aae79cf6f
Author: Lee Rhodes <le...@users.noreply.github.com>
AuthorDate: Sun Jan 7 17:24:35 2024 -0800

    Bringing Kll test profiles up to date.
---
 src/main/java/org/apache/datasketches/Align.java   | 739 +++++++++++++++++++++
 .../java/org/apache/datasketches/DoubleBits.java   | 377 +++++++++++
 .../apache/datasketches/DoubleIntIntTriple.java    |  86 +++
 .../java/org/apache/datasketches/DoublePair.java   |   4 +
 .../org/apache/datasketches/FloatIntIntTriple.java |  85 +++
 src/main/java/org/apache/datasketches/Job.java     |   8 +-
 .../org/apache/datasketches/SpecialRandom.java     |  85 +++
 .../characterization/AccuracyStats.java            |   6 +-
 .../datasketches/characterization/Shuffle.java     |  36 +-
 ...llDoublesSketchRankGaussianAccuracyProfile.java |  87 ++-
 .../kll/KllSketchAccuracyProfile.java              | 372 -----------
 .../kll/KllWorstCaseSketchAccuracyProfile.java     | 280 ++++++++
 .../uniquecount/BaseAccuracyProfile.java           |   2 +-
 .../KllDoublesSketchRankGaussianAccuracyJob.conf   |  20 +-
 ...Job.conf => KllWorstCaseSketchAccuracyJob.conf} |  12 +-
 15 files changed, 1768 insertions(+), 431 deletions(-)

diff --git a/src/main/java/org/apache/datasketches/Align.java b/src/main/java/org/apache/datasketches/Align.java
new file mode 100755
index 0000000..86d7fa6
--- /dev/null
+++ b/src/main/java/org/apache/datasketches/Align.java
@@ -0,0 +1,739 @@
+/*
+ * 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;
+
+/**
+ * Provides simple alignment and fill functions for strings, boolean,integer
+ * primitives and double in fixed-width character fields.
+ * @author Lee Rhodes
+ */
+public class Align {
+  private static final String NULL = "null";
+
+  //LEFT
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with space characters, if needed. If arg (as a String) is longer than the
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @return left justified arg
+   */
+  public static String left(final String arg, final int colwidth) {
+    return left(arg, colwidth, ' ');
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @param pad The pad character to fill any positions to the right of the
+   * given argument, if needed.
+   * @return left justified arg
+   */
+  public static String left(final String arg, final int colwidth, final char pad) {
+    if (colwidth < 1) { return ""; }
+    final String s = (arg == null) ? NULL : arg;
+    final int slen = s.length();
+    final char[] buf = new char[colwidth];
+    int pads = colwidth - slen;
+    if (pads > 0) {
+      s.getChars(0, slen, buf, 0);
+      for (int i = colwidth; i-- > slen;) {
+        buf[i] = pad;
+      }
+    }
+    else {
+      pads = -pads;
+      s.getChars(0, colwidth, buf, 0);
+    }
+    return new String(buf);
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with space characters, if needed. If arg (as a String) is longer than the
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @return left justified arg
+   */
+  public static String left(final long arg, final int colwidth) {
+    return left(Long.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @param pad The pad character to fill any positions to the right of the
+   * given argument, if needed.
+   * @return left justified arg
+   */
+  public static String left(final long arg, final int colwidth, final char pad) {
+    return left(Long.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with space characters, if needed. If arg (as a String) is longer than the
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @return left justified arg
+   */
+  public static String left(final int arg, final int colwidth) {
+    return left(Integer.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @param pad The pad character to fill any positions to the right of the
+   * given argument, if needed.
+   * @return left justified arg
+   */
+  public static String left(final int arg, final int colwidth, final char pad) {
+    return left(Integer.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with space characters, if needed. If arg (as a String) is longer than the
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @return left justified arg
+   */
+  public static String left(final short arg, final int colwidth) {
+    return left(Short.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @param pad The pad character to fill any positions to the right of the
+   * given argument, if needed.
+   * @return left justified arg
+   */
+  public static String left(final short arg, final int colwidth, final char pad) {
+    return left(Short.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with space characters, if needed. If arg (as a String) is longer than the
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @return left justified arg
+   */
+  public static String left(final byte arg, final int colwidth) {
+    return left(Byte.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @param pad The pad character to fill any positions to the right of the
+   * given argument, if needed.
+   * @return left justified arg
+   */
+  public static String left(final byte arg, final int colwidth, final char pad) {
+    return left(Byte.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with space characters, if needed. If arg (as a String) is longer than the
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @return left justified arg
+   */
+  public static String left(final boolean arg, final int colwidth) {
+    return left(Boolean.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @param pad The pad character to fill any positions to the right of the
+   * given argument, if needed.
+   * @return left justified arg
+   */
+  public static String left(final boolean arg, final int colwidth, final char pad) {
+    return left(Boolean.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with space characters, if needed. If arg (as a String) is longer than the
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @return left justified arg
+   */
+  public static String left(final double arg, final int colwidth) {
+    return left(Double.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Left justifies arg (as a String) within colwidth filling in the right
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the right.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * left justified.
+   * @param pad The pad character to fill any positions to the right of the
+   * given argument, if needed.
+   * @return left justified arg
+   */
+  public static String left(final double arg, final int colwidth, final char pad) {
+    return left(Double.toString(arg), colwidth, pad);
+  }
+
+  //RIGHT
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with space characters, if needed. If arg (as a String) is longer than
+   * the colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @return right justified arg
+   */
+  public static String right(final String arg, final int colwidth) {
+    return right(arg, colwidth, ' ');
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @param pad The pad character to fill any positions to the left of the
+   * given argument, if needed.
+   * @return right justified arg
+   */
+  public static String right(final String arg, final int colwidth, final char pad) {
+    if (colwidth < 1) { return ""; }
+    final String s = (arg == null) ? NULL : arg;
+    final int slen = s.length();
+    final char[] buf = new char[colwidth];
+    int pads = colwidth - slen;
+    if (pads > 0) {
+      s.getChars(0, slen, buf, pads);
+      for (int i = pads; i-- > 0;) {
+        buf[i] = pad;
+      }
+    }
+    else { //string is longer than colwidth
+      pads = -pads;
+      s.getChars(pads, slen, buf, 0);
+    }
+    return new String(buf);
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with space characters, if needed. If arg (as a String) is longer than
+   * the colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @return right justified arg
+   */
+  public static String right(final long arg, final int colwidth) {
+    return right(Long.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @param pad The pad character to fill any positions to the left of the
+   * given argument, if needed.
+   * @return right justified arg
+   */
+  public static String right(final long arg, final int colwidth, final char pad) {
+    return right(Long.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with space characters, if needed. If arg (as a String) is longer than
+   * the colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @return right justified arg
+   */
+  public static String right(final int arg, final int colwidth) {
+    return right(Integer.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @param pad The pad character to fill any positions to the left of the
+   * given argument, if needed.
+   * @return right justified arg
+   */
+  public static String right(final int arg, final int colwidth, final char pad) {
+    return right(Integer.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with space characters, if needed. If arg (as a String) is longer than
+   * the colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @return right justified arg
+   */
+  public static String right(final short arg, final int colwidth) {
+    return right(Short.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @param pad The pad character to fill any positions to the left of the
+   * given argument, if needed.
+   * @return right justified arg
+   */
+  public static String right(final short arg, final int colwidth, final char pad) {
+    return right(Short.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with space characters, if needed. If arg (as a String) is longer than
+   * the colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @return right justified arg
+   */
+  public static String right(final byte arg, final int colwidth) {
+    return right(Byte.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @param pad The pad character to fill any positions to the left of the
+   * given argument, if needed.
+   * @return right justified arg
+   */
+  public static String right(final byte arg, final int colwidth, final char pad) {
+    return right(Byte.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with space characters, if needed. If arg (as a String) is longer than
+   * the colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @return right justified arg
+   */
+  public static String right(final boolean arg, final int colwidth) {
+    return right(Boolean.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @param pad The pad character to fill any positions to the left of the
+   * given argument, if needed.
+   * @return right justified arg
+   */
+  public static String right(final boolean arg, final int colwidth, final char pad) {
+    return right(Boolean.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with space characters, if needed. If arg (as a String) is longer than
+   * the colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @return right justified arg
+   */
+  public static String right(final double arg, final int colwidth) {
+    return right(Double.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Right justifies arg (as a String) within colwidth filling in the left
+   * with the pad character, if needed. If arg (as a String) is longer than
+   * colwidth, it truncates on the left.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given argument is
+   * right justified.
+   * @param pad The pad character to fill any positions to the left of the
+   * given argument, if needed.
+   * @return right justified arg
+   */
+  public static String right(final double arg, final int colwidth, final char pad) {
+    return right(Double.toString(arg), colwidth, pad);
+  }
+
+  //CENTER
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with
+   * space characters, if needed.  If arg (as a String) is longer than
+   * colwidth, it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @return centered arg
+   */
+  public static String center(final String arg, final int colwidth) {
+    return center(arg, colwidth, ' ');
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with the
+   * pad character, if needed. If arg (as a String) is longer than colwidth,
+   * it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @param pad The pad character to fill any positions to the sides of the
+   * given argument (as a String), if needed.
+   * @return centered arg
+   */
+  public static String center(final String arg, final int colwidth, final char pad) {
+    if (colwidth < 1) { return ""; }
+    final String s = (arg == null) ? NULL : arg;
+    final int slen = s.length();
+    final char[] buf = new char[colwidth];
+    int pads = colwidth - slen;
+    if (pads > 0) {
+      for (int i = colwidth; i-- > 0;) { buf[i] = pad; }
+      s.getChars(0, slen, buf, pads / 2);
+    }
+    else {
+      pads = (-pads) / 2;
+      s.getChars(pads, pads + colwidth, buf, 0);
+    }
+    return new String(buf);
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with
+   * space characters, if needed.  If arg (as a String) is longer than
+   * colwidth, it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @return centered arg
+   */
+  public static String center(final long arg, final int colwidth) {
+    return center(Long.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with the
+   * pad character, if needed. If arg (as a String) is longer than colwidth,
+   * it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @param pad The pad character to fill any positions to the sides of the
+   * given argument (as a String), if needed.
+   * @return centered arg
+   */
+  public static String center(final long arg, final int colwidth, final char pad) {
+    return center(Long.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with
+   * space characters, if needed.  If arg (as a String) is longer than
+   * colwidth, it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @return centered arg
+   */
+  public static String center(final int arg, final int colwidth) {
+    return center(Integer.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with the
+   * pad character, if needed. If arg (as a String) is longer than colwidth,
+   * it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @param pad The pad character to fill any positions to the sides of the
+   * given argument (as a String), if needed.
+   * @return centered arg
+   */
+  public static String center(final int arg, final int colwidth, final char pad) {
+    return center(Integer.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with
+   * space characters, if needed.  If arg (as a String) is longer than
+   * colwidth, it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @return centered arg
+   */
+  public static String center(final short arg, final int colwidth) {
+    return center(Short.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with the
+   * pad character, if needed. If arg (as a String) is longer than colwidth,
+   * it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @param pad The pad character to fill any positions to the sides of the
+   * given argument (as a String), if needed.
+   * @return centered arg
+   */
+  public static String center(final short arg, final int colwidth, final char pad) {
+    return center(Short.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with
+   * space characters, if needed.  If arg (as a String) is longer than
+   * colwidth, it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @return centered arg
+   */
+  public static String center(final byte arg, final int colwidth) {
+    return center(Byte.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with the
+   * pad character, if needed. If arg (as a String) is longer than colwidth,
+   * it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @param pad The pad character to fill any positions to the sides of the
+   * given argument (as a String), if needed.
+   * @return centered arg
+   */
+  public static String center(final byte arg, final int colwidth, final char pad) {
+    return center(Byte.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with
+   * space characters, if needed.  If arg (as a String) is longer than
+   * colwidth, it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @return centered arg
+   */
+  public static String center(final boolean arg, final int colwidth) {
+    return center(Boolean.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with the
+   * pad character, if needed. If arg (as a String) is longer than colwidth,
+   * it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @param pad The pad character to fill any positions to the sides of the
+   * given argument (as a String), if needed.
+   * @return centered arg
+   */
+  public static String center(final boolean arg, final int colwidth, final char pad) {
+    return center(Boolean.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with
+   * space characters, if needed.  If arg (as a String) is longer than
+   * colwidth, it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @return centered arg
+   */
+  public static String center(final double arg, final int colwidth) {
+    return center(Double.toString(arg), colwidth, ' ');
+  }
+
+  /**
+   * Centers arg (as a String) within colwidth filling in the sides with the
+   * pad character, if needed. If arg (as a String) is longer than colwidth,
+   * it truncates on both sides.
+   *
+   * @param arg The given argument.
+   * @param colwidth The width of the space into which the given
+   * argument (as a String) is centered.
+   * @param pad The pad character to fill any positions to the sides of the
+   * given argument (as a String), if needed.
+   * @return centered arg
+   */
+  public static String center(final double arg, final int colwidth, final char pad) {
+    return center(Double.toString(arg), colwidth, pad);
+  }
+
+  /**
+   * Example and test.
+   * @param args input parameters
+   */
+  public static void main(final String[] args) {
+    final String s = "This is a string";
+    final String left = "->|";
+    final String right = "|<-";
+    final String out = left + center(s,14) + right;
+    println(out);
+  }
+
+  private final static boolean enablePrinting = true;
+
+  /**
+   * @param format the format
+   * @param args the args
+   */
+  @SuppressWarnings("unused")
+  private static final void printf(final String format, final Object ... args) {
+    if (enablePrinting) { System.out.printf(format, args); }
+  }
+
+  /**
+   * @param o the Object to println
+   */
+  private static final void println(final Object o) {
+    if (enablePrinting) { println(o.toString()); }
+  }
+
+}
diff --git a/src/main/java/org/apache/datasketches/DoubleBits.java b/src/main/java/org/apache/datasketches/DoubleBits.java
new file mode 100755
index 0000000..2f7fc0c
--- /dev/null
+++ b/src/main/java/org/apache/datasketches/DoubleBits.java
@@ -0,0 +1,377 @@
+/*
+ * 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;
+
+import org.testng.annotations.Test;
+
+/**
+ * If you are developing any functions that operate directly on the IEEE 754
+ * double-precision 64-bit fields you will need this class.
+ * @author Lee Rhodes
+ */
+public final class DoubleBits {
+  public static final long SIGN = 1L << 63; //only the MSB (sign) set
+  public static final long DEXP1 = 1L << 52; //an exponent value of 1
+  public static final long DEXP2 = 2L << 52; //an exponent value of 2
+  public static final long DMANMASK = DEXP1 - 1L; //mantissa mask (52 1's)
+  public static final long DEXP1023 = 1023L << 52; //exp = 1023 (10 1's)
+  public static final long DEXP1025 = 1025L << 52; //exp = 1025
+  public static final long DEXP1026 = 1026L << 52; //exp = 1026
+  public static final long DEXPMASK = 2047L << 52;//exp = 2047 (11 1's), mask.
+
+  private DoubleBits() {
+    //Empty Constructor
+  }
+
+  /**
+   * Returns true if the IEEE 754 sign bit is set even if the value represents a NaN or zero.
+   * @param d the given double
+   * @return the sign bit.
+   */
+  public static boolean isNegative(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return ((bits & SIGN) != 0L);
+  }
+
+  /**
+   * Returns true if the value is a +/- denormalized number but not +/- zero.
+   * @param d the given double
+   * @return true if the value is a +/- denormalized number but not +/- zero.
+   */
+  public static boolean isDenormal(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return (d != 0.0) && ((bits & DEXPMASK) == 0L) ;
+  }
+
+  /**
+   * Returns true if the value is +/- Infinity
+   * @param d the given double
+   * @return true if the value is +/- Infinity
+   */
+  public static boolean isInfinity(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return ((bits & ~SIGN) == DEXPMASK);
+  }
+
+  /**
+   * Returns true if the value is not a NaN or Infinity
+   * @param d the given double
+   * @return true if the value is not a NaN or Infinity
+   */
+  public static boolean isValid(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return ((bits & DEXPMASK) != DEXPMASK);
+  }
+
+  /**
+   * Returns true if the value is a valid argument for the log function.
+   * In other words, it cannot be +/- NaN, zero, or Infinity, but it may
+   * be a denormal number.
+   * @param d the given double
+   * @return true if the value is a valid argument for the log function
+   */
+  public static boolean isValidLogArgument(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return ((bits + DEXP1) > DEXP1);
+  }
+
+  /**
+   * Returns true if the value is a denormal or not a valid argument for the log function.
+   * @param d the given double
+   * @return true if the value is a denormal or not a valid argument for the log function.
+   */
+  public static boolean isDenormalOrNotValidLogArgument(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return ((bits + DEXP1) < DEXP2);
+  }
+
+  /**
+   * Returns the signum function of the argument; zero if the argument
+   * is zero, 1.0 if the argument is greater than zero, -1.0 if the
+   * argument is less than zero.  If the argument is +/- NaN or zero,
+   * the result is the same as the argument.<br/>
+   *
+   * <p>Note that this is a faster, simpler replacement for the needlessly
+   * complicated implementation in sun.misc.FpUtils.</p>
+   *
+   * @param d the given double
+   * @return the signum function of the argument
+   */
+  public static double signum(final double d) {
+    return ((d != d) || (d == 0.0)) ? d : (d < 0.0) ? -1.0 : 1.0;
+  }
+
+  /**
+   * Returns the 11 bit exponent of a double flush right as an int.
+   * @param d the given double
+   * @return the exponent bits.
+   */
+  public static int exponentToIntBits(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return (int)((bits & DEXPMASK) >>> 52);
+  }
+
+  /**
+   * Returns the 52 bits of the mantissa as a long.
+   * @param d the given double
+   * @return the mantissa bits.
+   */
+  public static long mantissaToLongBits(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return bits & DMANMASK;
+  }
+
+  /**
+   * Returns the mathematical Base 2 exponent as an int. The offset
+   * has been removed.
+   * @param d the given double
+   * @return the mathematical Base 2 exponent
+   */
+  public static int base2Exponent(final double d) {
+    final int e = exponentToIntBits(d);
+    return (e == 0) ? -1022 : e - 1023;
+  }
+
+  /**
+   * Given the double value d, replace the exponent bits
+   * with the raw exponent value provided in exp.  If you are converting from
+   * a mathematical Base 2 exponent, the offset of 1023 must be added first.
+   * @param d the given double
+   * @param exp the given exponent as raw bits
+   * @return the double value d with replaced exponent bits
+   */
+  public static double setRawExponentBits(final double d, final int exp) {
+    long bits = Double.doubleToRawLongBits(d);
+    bits &= ~DEXPMASK; //remove old exponent bits
+    bits |= (exp & 0x7FFL) << 52;//insert the new exponent
+    return Double.longBitsToDouble(bits);
+  }
+
+  /**
+   * Given the double value d, replace the mantissa bits
+   * with the given mantissa.
+   * @param d the given double
+   * @param man the given mantissa
+   * @return the double value d with replaced mantissa bits
+   */
+  public static double setMantissaBits(final double d, final long man) {
+    long bits = Double.doubleToRawLongBits(d);
+    bits &= ~DMANMASK; //remove old mantissa bits
+    bits |= (DMANMASK & man); //insert the new mantissa
+    return Double.longBitsToDouble(bits);
+  }
+
+  /**
+   * Returns the given double with the sign bit set as specified by the given boolean.
+   * @param d the given double
+   * @param negative desired value
+   * @return the given double with the sign bit set as specified by the given boolean.
+   */
+  public static double setSignBit(final double d, final boolean negative) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return negative
+        ? Double.longBitsToDouble(bits | SIGN)
+            : Double.longBitsToDouble(bits & ~SIGN);
+  }
+
+  /**
+   * Given a double, this returns a decimal value representing the effective
+   * fractional value of the double's mantissa, which is independent of the
+   * value of the exponent with only one exception. If the exponent field 'e'
+   * of a double is in the range [1, 2046] the value of a double can be
+   * expressed mathematically as 1.fraction X 2^(e-1023). If the exponent
+   * value e == 0, the value is expressed as 0.fraction X 2^(-1022), which is
+   * called a denormal number. Denormal numbers are only required for
+   * magnitudes less than 2.2250738585072014E-308. Very small indeed and much
+   * smaller than normal rounding errors.
+   *
+   * @param d the given double
+   * @return a value representing the fractional value of the
+   *         double's mantissa. It will be in the format 1.fraction or
+   *         0.fraction depending on the exponent as explained above.
+   */
+  public static double mantissaFraction(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    final long exp = bits & DEXPMASK;
+    final long sign = bits & SIGN; //required in case d is a NaN or zero
+    //remove exp & sign, insert exponent for 1.0
+    final long man = (bits & DMANMASK) | DEXP1023;
+    double d2 = Double.longBitsToDouble(man); //back to double as 1.xxxxx
+    d2 = (exp == 0L) ? d2 - 1.0 : d2;
+    return (sign != 0L) ? -d2 : d2;
+  }
+
+  /**
+   * Returns the given double as a string of the form
+   * <pre>
+   *  SP.FFFFF...FFFBTEEEE
+   *  Where
+   *    S = the sign of the magnitude only if negative, no space if positive
+   *    P = mantissa prefix of 1 or 0
+   *    F = decimal fraction
+   *    B = indicates binary power of 2 representation
+   *    T = the sign of the exponent only if negative
+   *    E = the exponent of 2
+   * </pre>
+   * @param d the given double
+   * @return the given double as a string
+   */
+  public static String doubleToBase2String(final double d) {
+    final boolean sign = isNegative(d);
+    if (d == 0.0) { return sign ? "-0.0B0" : "0.0B0"; }
+    return Double.toString(mantissaFraction(d)) + "B" + base2Exponent(d);
+  }
+
+  /**
+   * Returns a formatted string representing the fields of an
+   * IEEE 754 64-bit double-precision floating point value.
+   * The output string is in the form:
+   * <pre>
+   *  S EEEEEEEEEEE MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+   * </pre>
+   * where S represents the sign bit, E represents bits of the Exponent field,
+   * and M represents bits of the Mantissa field of the double value.
+   * @param d the given double
+   * @return the formatted string of the fields of a <i>double</i>.
+   */
+  public static String doubleToBitString(final double d) {
+    final long bits = Double.doubleToRawLongBits(d);
+    return longBitsToDoubleBitString(bits);
+  }
+
+  /**
+   * Returns a formatted string representing the fields of an
+   * IEEE 754 64-bit double-precision floating point value presented as a
+   * <i>long</i>.  The output string is in the form:
+   * <pre>
+   *  S EEEEEEEEEEE MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+   * </pre>
+   * where S represents the sign bit, E represents bits of the Exponent field,
+   * and M represents bits of the Mantissa field of the double value.
+   * @param bits the <i>double</i> value in the form of a <i>long</i> to be
+   * examined.
+   * @return the formatted string of the fields of a <i>double</i>.
+   */
+  public static String longBitsToDoubleBitString(final long bits) {
+    final int intSign = ((bits & SIGN) != 0L) ? 1 : 0;
+    final int e = (int)((bits & DEXPMASK) >>> 52);
+    final String estr = Align.right(Integer.toBinaryString(e), 11, '0');
+    final long m = bits & DMANMASK;
+    final String mstr = Align.right(Long.toBinaryString(m), 52, '0');
+    return intSign + " " + estr + " " + mstr;
+  }
+
+  /**
+   * Helper method to determine whether a specified string is a
+   * parsable numeric value or not.
+   *
+   * @param string the input string to analyze.
+   *
+   * @return true if the value is numeric (integer, float, double); false if
+   *         not.
+   */
+  public static boolean isNumeric(final String string) {
+
+    boolean isNum = false;
+
+    try {
+
+      Double.parseDouble(string);
+      isNum = true;
+
+    }  catch (final NumberFormatException exc ) {
+      // We have a non numeric value.
+    }
+
+    return isNum;
+  }
+
+  private static void checkDoubleBits(final double d, final String txt) {
+    println("Test     :" + txt);
+    println("Value    : " + d);
+    println("Bits     : " + doubleToBitString(d));
+    println("Base2    : " + doubleToBase2String(d));
+    println("Negative : " + isNegative(d));
+    println("Denormal : " + isDenormal(d));
+    println("Infinity : " + isInfinity(d));
+    println("Valid    : " + isValid(d));
+    println("Valid Log: " + isValidLogArgument(d));
+    println("Signum   : " + signum(d));
+    println("");
+  }
+
+  @Test
+  public static void doubleBitsTest() {
+    checkDoubleBits(4.9E-324,"+Denormal");
+    checkDoubleBits(-4.9E-324,"-Denormal");
+    checkDoubleBits(0.0,"+Zero");
+    checkDoubleBits(-0.0,"-Zero");
+    checkDoubleBits(1.0,"+1.0");
+    checkDoubleBits(-1.0,"-1.0");
+    checkDoubleBits(Double.MAX_VALUE,"MAX_VALUE");
+    checkDoubleBits(Double.MIN_VALUE,"MIN_VALUE");
+    checkDoubleBits(Double.POSITIVE_INFINITY,"+INFINITY");
+    checkDoubleBits(Double.NEGATIVE_INFINITY,"-INFINITY");
+    checkDoubleBits(Double.NaN,"+QNaN"); //Quiet NaN
+    checkDoubleBits(setSignBit(Double.NaN, true),"-QNaN"); //-Quiet NaN
+  }
+
+  /**
+   * The maximum integral value that a double can resolve exactly is 8PebiBytes
+   * or (1L << 53).
+   */
+  @Test
+  public static void checkMaxIntegralPrcisionOfDouble() {
+    final double EIGHT_PEBI = (1L << 53);
+    println(doubleToBitString(EIGHT_PEBI + 1L) + ", " + Double.toString(EIGHT_PEBI + 1L)); //over the limit
+    println(doubleToBitString(EIGHT_PEBI) + ", " + Double.toString(EIGHT_PEBI));
+    println(doubleToBitString(EIGHT_PEBI - 1L) + ", " + Double.toString(EIGHT_PEBI - 1L));
+  }
+
+  /**
+   * The maximum integral value that a float can resolve exactly is 16MebiBytes
+   * or (1 << 24).
+   */
+  @Test
+  public static void checkMaxIntegralPrcisionOfFloat() {
+    final float SIXTEEN_MEBI = (1 << 24);
+    println(Float.toString(SIXTEEN_MEBI + 1)); //over the limit
+    println(Float.toString(SIXTEEN_MEBI));
+    println(Float.toString(SIXTEEN_MEBI - 1));
+  }
+
+  private final static boolean enablePrinting = true;
+
+  /**
+   * @param format the format
+   * @param args the args
+   */
+  @SuppressWarnings("unused")
+  private static final void printf(final String format, final Object ... args) {
+    if (enablePrinting) { System.out.printf(format, args); }
+  }
+
+  /**
+   * @param o the Object to println
+   */
+  private static final void println(final Object o) {
+    if (enablePrinting) { System.out.println(o.toString()); }
+  }
+}
diff --git a/src/main/java/org/apache/datasketches/DoubleIntIntTriple.java b/src/main/java/org/apache/datasketches/DoubleIntIntTriple.java
new file mode 100644
index 0000000..a99b9e3
--- /dev/null
+++ b/src/main/java/org/apache/datasketches/DoubleIntIntTriple.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * A triple (double value, int index, int rank) with sorting.
+ */
+public class DoubleIntIntTriple {
+  public double value;
+  public int index;
+  public int rank;
+  private static final CompareValue compValue = new CompareValue();
+  private static final CompareIndex compIndex = new CompareIndex();
+  private static final CompareRank compRank = new CompareRank();
+
+  public static final DoubleIntIntTriple[] sortByValue(final DoubleIntIntTriple[] array) {
+    Arrays.sort(array, compValue);
+    return array;
+  }
+
+  public static final DoubleIntIntTriple[] sortByIndex(final DoubleIntIntTriple[] array) {
+    Arrays.sort(array, compIndex);
+    return array;
+  }
+
+  public static final DoubleIntIntTriple[] sortByRank(final DoubleIntIntTriple[] array) {
+    Arrays.sort(array, compRank);
+    return array;
+  }
+
+  public static final double[] getValueArray(final DoubleIntIntTriple[] array) {
+    final int len = array.length;
+    final double[] out = new double[len];
+    for (int i = 0; i < len; i++) { out[i] = array[i].value; }
+    return out;
+  }
+
+  public static final int[] getRankArray(final DoubleIntIntTriple[] array) {
+    final int len = array.length;
+    final int[] out = new int[len];
+    for (int i = 0; i < len; i++) { out[i] = array[i].rank; }
+    return out;
+  }
+
+  private static final class CompareValue implements Comparator<DoubleIntIntTriple> {
+    @Override
+    public int compare(final DoubleIntIntTriple t1, final DoubleIntIntTriple t2) {
+      return Double.compare(t1.value, t2.value); // handles NaN, +/- 0, etc.
+    }
+  }
+
+  private static final class CompareIndex implements Comparator<DoubleIntIntTriple> {
+    @Override
+    public int compare(final DoubleIntIntTriple t1, final DoubleIntIntTriple t2) {
+      return Integer.compare(t1.index, t2.index);
+    }
+  }
+
+  private static final class CompareRank implements Comparator<DoubleIntIntTriple> {
+    @Override
+    public int compare(final DoubleIntIntTriple t1, final DoubleIntIntTriple t2) {
+      return Integer.compare(t1.rank, t2.rank);
+    }
+  }
+
+}
diff --git a/src/main/java/org/apache/datasketches/DoublePair.java b/src/main/java/org/apache/datasketches/DoublePair.java
index 3b14a67..b18d7f6 100644
--- a/src/main/java/org/apache/datasketches/DoublePair.java
+++ b/src/main/java/org/apache/datasketches/DoublePair.java
@@ -21,6 +21,9 @@ package org.apache.datasketches;
 
 import java.util.Comparator;
 
+/**
+ * A pair (double x, double y) with a comparator on x.
+ */
 public class DoublePair implements Comparator<DoublePair> {
   public double x;
   public double y;
@@ -34,4 +37,5 @@ public class DoublePair implements Comparator<DoublePair> {
   public int compare(final DoublePair p1, final DoublePair p2) {
     return Double.compare(p1.x, p2.x); // handles NaN, +/- 0, etc.
   }
+
 }
diff --git a/src/main/java/org/apache/datasketches/FloatIntIntTriple.java b/src/main/java/org/apache/datasketches/FloatIntIntTriple.java
new file mode 100644
index 0000000..ec8d7c2
--- /dev/null
+++ b/src/main/java/org/apache/datasketches/FloatIntIntTriple.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * A triple (float value, int index, int rank) with sorting.
+ */
+public class FloatIntIntTriple {
+  public float value;
+  public int index;
+  public int rank;
+  private static final CompareValue compValue = new CompareValue();
+  private static final CompareIndex compIndex = new CompareIndex();
+  private static final CompareRank compRank = new CompareRank();
+
+  public static final FloatIntIntTriple[] sortByValue(final FloatIntIntTriple[] array) {
+    Arrays.sort(array, compValue);
+    return array;
+  }
+
+  public static final FloatIntIntTriple[] sortByIndex(final FloatIntIntTriple[] array) {
+    Arrays.sort(array, compIndex);
+    return array;
+  }
+
+  public static final FloatIntIntTriple[] sortByRank(final FloatIntIntTriple[] array) {
+    Arrays.sort(array, compRank);
+    return array;
+  }
+
+  public static final float[] getValueArray(final FloatIntIntTriple[] array) {
+    final int len = array.length;
+    final float[] out = new float[len];
+    for (int i = 0; i < len; i++) { out[i] = array[i].value; }
+    return out;
+  }
+
+  public static final int[] getRankArray(final FloatIntIntTriple[] array) {
+    final int len = array.length;
+    final int[] out = new int[len];
+    for (int i = 0; i < len; i++) { out[i] = array[i].rank; }
+    return out;
+  }
+
+  private static final class CompareValue implements Comparator<FloatIntIntTriple> {
+    @Override
+    public int compare(final FloatIntIntTriple t1, final FloatIntIntTriple t2) {
+      return Float.compare(t1.value, t2.value); // handles NaN, +/- 0, etc.
+    }
+  }
+
+  private static final class CompareIndex implements Comparator<FloatIntIntTriple> {
+    @Override
+    public int compare(final FloatIntIntTriple t1, final FloatIntIntTriple t2) {
+      return Integer.compare(t1.index, t2.index);
+    }
+  }
+
+  private static final class CompareRank implements Comparator<FloatIntIntTriple> {
+    @Override
+    public int compare(final FloatIntIntTriple t1, final FloatIntIntTriple t2) {
+      return Integer.compare(t1.rank, t2.rank);
+    }
+  }
+}
diff --git a/src/main/java/org/apache/datasketches/Job.java b/src/main/java/org/apache/datasketches/Job.java
index 0f28ef2..f170d42 100644
--- a/src/main/java/org/apache/datasketches/Job.java
+++ b/src/main/java/org/apache/datasketches/Job.java
@@ -81,13 +81,8 @@ public class Job {
       throw new IllegalStateException("Could not configure PrintWriters.");
     }
     //OUTPUT ORDER
-
     println("START JOB " + profileName );
     println("Date Time: " + readableSimpleDateFmt.format(date));
-    println("");
-    println("PROPERTIES:");
-    println(prop.extractKvPairs(LS));
-    flush(); //flush print buffer
 
     /***RUN THE PROFILE ****************/
     startTime_mS = System.currentTimeMillis();
@@ -98,6 +93,9 @@ public class Job {
     /***********************************/
 
     println("");
+    println("PROPERTIES:");
+    println(prop.extractKvPairs(LS));
+
     println("Total Job Time: " + milliSecToString(testTime_mS));
     println("END JOB " + profileName +  LS + LS);
     flush();
diff --git a/src/main/java/org/apache/datasketches/SpecialRandom.java b/src/main/java/org/apache/datasketches/SpecialRandom.java
new file mode 100644
index 0000000..f00a852
--- /dev/null
+++ b/src/main/java/org/apache/datasketches/SpecialRandom.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+/**
+ * This SpecialRandom generator extends the java.util.Random to include some important missing methods.
+ */
+public class SpecialRandom extends java.util.Random {
+  /** use serialVersionUID from JDK 1.1 for interoperability */
+  static final long serialVersionUID = 3905348978240129619L;
+
+  /**
+   * Constructs a new special random generator.
+   */
+  public SpecialRandom() {
+    super();
+  }
+
+  /**
+   * Provides a seed to make this generator deterministic.
+   * @param seed the given seed.
+   */
+  public SpecialRandom(final long seed) {
+    super(seed);
+  }
+
+  /**
+   * This makes visible an important hidden class from Random. It provides the next pseudorandom integer value
+   * consisting of the number given bits as low order bits.
+   * @param bits the number of random low-order bits from the range [1, 32] (inclusive, inclusive)
+   * @return the next pseudorandom value consisting of <i>bits</i> low-order bits.
+   */
+  @Override
+  public int next(final int bits) {
+    return super.next(bits);
+  }
+
+  /**
+   * This provides the next pseudorandom long value consisting of the number of given bits as low order bits.
+   * @param bits the number of random low-order bits from the range [1, 64] (inclusive, inclusive)
+   * @return the next pseudorandom value consisting of <i>bits</i> low-order bits.
+   */
+  public long nextLong(final int bits) {
+    if (bits <= 32) { return next(bits); }
+    return ((long)(next(bits - 32)) << 32) + next(32);
+  }
+
+  /**
+   * Returns an approximate uniform random distribution of long values between 0 (inclusive) and bound (exclusive);
+   * @param bound a value from the range [2, bound).
+   * @return an approximate uniform random long from the range [2, bound).
+   */
+  public long nextLong(final long bound) {
+    if (bound <= 1L) { throw new IllegalArgumentException("bound must be greater than 1"); }
+    final long m = bound - 1L;
+    long r;
+    if ((bound & m) == 0) { //bound is power of 2
+      final int nlz = Long.numberOfLeadingZeros(bound);
+      final int bits = 64 - nlz - 1;
+      r = nextLong(bits);
+    } else {
+      r = nextLong(63);
+      for (long u = r; u - (r = u % bound) + m < 0; u = nextLong(63)) { }
+    }
+    return r;
+  }
+
+}
diff --git a/src/main/java/org/apache/datasketches/characterization/AccuracyStats.java b/src/main/java/org/apache/datasketches/characterization/AccuracyStats.java
index 331d545..0a7a3d3 100644
--- a/src/main/java/org/apache/datasketches/characterization/AccuracyStats.java
+++ b/src/main/java/org/apache/datasketches/characterization/AccuracyStats.java
@@ -40,7 +40,7 @@ public class AccuracyStats {
   public double sumSqErr = 0;
   public double rmsre = 0; //used later for plotting, set externally
   public double trueValue; //set by constructor, used only for error analysis
-  public long uniques;     //set by constructor, used as a coordinate
+  public long uniques;     //set by constructor, used as a coordinate for intersection
   public int bytes = 0;
 
   /**
@@ -123,8 +123,8 @@ public class AccuracyStats {
 
   /**
    * Build the AccuracyStats Array based on fractional powers of 10
-   * @param log10Min log_base2 of the minimum number of uniques used
-   * @param log10Max log_base2 of the maximum number of uniques used
+   * @param log10Min log_base10 of the minimum number of uniques used
+   * @param log10Max log_base10 of the maximum number of uniques used
    * @param ppb the number of points per base (10)
    * @param lgQK the lgK for the Quantiles sketch
    * @return an AccuracyStats array
diff --git a/src/main/java/org/apache/datasketches/characterization/Shuffle.java b/src/main/java/org/apache/datasketches/characterization/Shuffle.java
index 340b02e..62596dc 100644
--- a/src/main/java/org/apache/datasketches/characterization/Shuffle.java
+++ b/src/main/java/org/apache/datasketches/characterization/Shuffle.java
@@ -30,13 +30,15 @@ public final class Shuffle {
   /**
    * Shuffle the given input float array
    * @param array input array
+   * @return the given array, shuffled.
    */
-  public static void shuffle(final float[] array) {
+  public static float[] shuffle(final float[] array) {
     final int arrLen = array.length;
     for (int i = 0; i < arrLen; i++) {
       final int r = rand.nextInt(i + 1);
       swap(array, i, r);
     }
+    return array;
   }
 
   private static void swap(final float[] array, final int i1, final int i2) {
@@ -48,13 +50,15 @@ public final class Shuffle {
   /**
    * Shuffle the given input double array
    * @param array input array
+   * @return the given array, shuffled.
    */
-  public static void shuffle(final double[] array) {
+  public static double[] shuffle(final double[] array) {
     final int arrLen = array.length;
     for (int i = 0; i < arrLen; i++) {
       final int r = rand.nextInt(i + 1);
       swap(array, i, r);
     }
+    return array;
   }
 
   private static void swap(final double[] array, final int i1, final int i2) {
@@ -66,13 +70,15 @@ public final class Shuffle {
   /**
    * Shuffle the given input long array
    * @param array input array
+   * @return the given array, shuffled.
    */
-  public static void shuffle(final long[] array) {
+  public static long[] shuffle(final long[] array) {
     final int arrLen = array.length;
     for (int i = 0; i < arrLen; i++) {
       final int r = rand.nextInt(i + 1);
       swap(array, i, r);
     }
+    return array;
   }
 
   private static void swap(final long[] array, final int i1, final int i2) {
@@ -84,13 +90,15 @@ public final class Shuffle {
   /**
    * Shuffle the given input int array
    * @param array input array
+   * @return the given array, shuffled.
    */
-  public static void shuffle(final int[] array) {
+  public static int[] shuffle(final int[] array) {
     final int arrLen = array.length;
     for (int i = 0; i < arrLen; i++) {
       final int r = rand.nextInt(i + 1);
       swap(array, i, r);
     }
+    return array;
   }
 
   private static void swap(final int[] array, final int i1, final int i2) {
@@ -99,4 +107,24 @@ public final class Shuffle {
     array[i2] = value;
   }
 
+  /**
+   * Shuffle the given input Object array
+   * @param array input array
+   * @return the given array, shuffled.
+   */
+  public static Object[] shuffle(final Object[] array) {
+    final int arrLen = array.length;
+    for (int i = 0; i < arrLen; i++) {
+      final int r = rand.nextInt(i + 1);
+      swap(array, i, r);
+    }
+    return array;
+  }
+
+  private static void swap(final Object[] array, final int i1, final int i2) {
+    final Object value = array[i1];
+    array[i1] = array[i2];
+    array[i2] = value;
+  }
+
 }
diff --git a/src/main/java/org/apache/datasketches/characterization/kll/KllDoublesSketchRankGaussianAccuracyProfile.java b/src/main/java/org/apache/datasketches/characterization/kll/KllDoublesSketchRankGaussianAccuracyProfile.java
index 6623a1d..280d452 100644
--- a/src/main/java/org/apache/datasketches/characterization/kll/KllDoublesSketchRankGaussianAccuracyProfile.java
+++ b/src/main/java/org/apache/datasketches/characterization/kll/KllDoublesSketchRankGaussianAccuracyProfile.java
@@ -22,11 +22,14 @@ package org.apache.datasketches.characterization.kll;
 import static java.lang.Math.round;
 import static org.apache.datasketches.GaussianRanks.GAUSSIANS_3SD;
 import static org.apache.datasketches.common.Util.pwr2SeriesNext;
+import static org.apache.datasketches.quantilescommon.QuantileSearchCriteria.EXCLUSIVE;
+import static org.apache.datasketches.quantilescommon.QuantileSearchCriteria.INCLUSIVE;
 import static org.apache.datasketches.quantilescommon.QuantilesUtil.evenlySpacedDoubles;
 
 import org.apache.datasketches.Job;
 import org.apache.datasketches.JobProfile;
 import org.apache.datasketches.MonotonicPoints;
+import org.apache.datasketches.Properties;
 import org.apache.datasketches.characterization.Shuffle;
 import org.apache.datasketches.kll.KllDoublesSketch;
 import org.apache.datasketches.memory.DefaultMemoryRequestServer;
@@ -34,6 +37,7 @@ import org.apache.datasketches.memory.WritableMemory;
 import org.apache.datasketches.quantiles.DoublesSketch;
 import org.apache.datasketches.quantiles.DoublesSketchBuilder;
 import org.apache.datasketches.quantiles.UpdateDoublesSketch;
+import org.apache.datasketches.quantilescommon.QuantileSearchCriteria;
 
 /**
  * @author Lee Rhodes
@@ -41,6 +45,7 @@ import org.apache.datasketches.quantiles.UpdateDoublesSketch;
 public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
   private static final DefaultMemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
   private Job job;
+  private Properties props;
 
   //FROM PROPERTIES
   //For computing the different stream lengths
@@ -57,6 +62,9 @@ public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
 
   //Target sketch configuration & error analysis
   private int k;
+  private QuantileSearchCriteria criteria;
+  private boolean useBulk;
+  private boolean direct;
 
   //DERIVED globals
   private KllDoublesSketch sk;
@@ -67,9 +75,9 @@ public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
 
   //Specific to a streamLength
   private double[] stream;
-  private double[] trueValues;
+  private double[] trueNaturalRanks;
   private int trueValueCorrection;
-  private double[] corrTrueValues;
+  private double[] corrNaturalRanks;
 
   private final String[] columnLabels =
     {"nPP", "Value", "Rank", "-3SD","-2SD", "-1SD", "Med", "+1SD", "+2SD", "+3SD"};
@@ -83,6 +91,7 @@ public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
   @Override
   public void start(final Job job) {
     this.job = job;
+    this.props = job.getProperties();
     extractProperties();
     configureCommon();
     doJob();
@@ -97,25 +106,27 @@ public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
 
   private void extractProperties() {
     //stream length
-    lgMin = Integer.parseInt(job.getProperties().mustGet("LgMin"));
-    lgMax = Integer.parseInt(job.getProperties().mustGet("LgMax"));
-    lgDelta = Integer.parseInt(job.getProperties().mustGet("LgDelta"));
-    ppo = Integer.parseInt(job.getProperties().mustGet("PPO"));
+    lgMin = Integer.parseInt(props.mustGet("LgMin"));
+    lgMax = Integer.parseInt(props.mustGet("LgMax"));
+    lgDelta = Integer.parseInt(props.mustGet("LgDelta"));
+    ppo = Integer.parseInt(props.mustGet("PPO"));
     //numTrials & error quantiles sketch config
-    numTrials = 1 << Integer.parseInt(job.getProperties().mustGet("LgTrials"));
-    errorSkLgK = Integer.parseInt(job.getProperties().mustGet("ErrSkLgK"));
+    numTrials = 1 << Integer.parseInt(props.mustGet("LgTrials"));
+    errorSkLgK = Integer.parseInt(props.mustGet("ErrSkLgK"));
     //plotting & x-axis config
-    numPlotPoints = Integer.parseInt(job.getProperties().mustGet("NumPlotPoints"));
+    numPlotPoints = Integer.parseInt(props.mustGet("NumPlotPoints"));
     //Target sketch config
-    k = Integer.parseInt(job.getProperties().mustGet("K"));
-
+    k = Integer.parseInt(props.mustGet("K"));
+    criteria = props.mustGet("criteria").equalsIgnoreCase("INCLUSIVE") ? INCLUSIVE : EXCLUSIVE;
+    useBulk = Boolean.parseBoolean(props.mustGet("useBulk"));
+    direct = Boolean.parseBoolean(props.mustGet("direct"));
   }
 
   void configureCommon() {
     configureSketch();
-    trueValues = new double[numPlotPoints];
-    corrTrueValues = new double[numPlotPoints];
-    trueValueCorrection = 1; //KLL is always LT
+    trueNaturalRanks = new double[numPlotPoints];
+    corrNaturalRanks = new double[numPlotPoints];
+    trueValueCorrection = (criteria == EXCLUSIVE) ? 1 : 0;
     errQSkArr = new UpdateDoublesSketch[numPlotPoints];
     //configure the error quantiles array
     final DoublesSketchBuilder builder = DoublesSketch.builder().setK(1 << errorSkLgK);
@@ -129,10 +140,12 @@ public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
   }
 
   void configureSketch() {
-    final WritableMemory wmem = WritableMemory.allocate(10000);
-    sk = KllDoublesSketch.newDirectInstance(k, wmem, memReqSvr);
-    //sk = KllDoublesSketch.newHeapInstance(k);
-    //sk = new KllDoublesSketch(k);
+    if (direct) {
+      final WritableMemory wmem = WritableMemory.allocate(10000);
+      sk = KllDoublesSketch.newDirectInstance(k, wmem, memReqSvr);
+    } else {
+      sk = KllDoublesSketch.newHeapInstance(k);
+    }
   }
 
   private void doJob() {
@@ -168,37 +181,37 @@ public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
     job.printfData(sFmt, (Object[])columnLabels);
 
     //build the stream
-    //the values themselves reflect their integer ranks starting with 1 (except for LT)
     stream = new double[streamLength];
     for (int sl = 1; sl <= streamLength; sl++) { stream[sl - 1] = sl; } //1 to SL
 
     //compute the true values used at the plot points
     final double start = 1.0;
     final double end = streamLength;
-    final double[] dblValues = evenlySpacedDoubles(start, end, numPlotPoints);
+    //approxDblNatRanks are designed to be their natural ranks starting with 1
+    final double[] approxDblNatRanks = evenlySpacedDoubles(start, end, numPlotPoints);
 
     for (int pp = 0; pp < numPlotPoints; pp++) {
-      trueValues[pp] = round(dblValues[pp]);
-      corrTrueValues[pp] = trueValues[pp] - trueValueCorrection;
+      trueNaturalRanks[pp] = round(approxDblNatRanks[pp]); //force nearest integer
+      corrNaturalRanks[pp] = trueNaturalRanks[pp] - trueValueCorrection; //minus: exclusive = 1, inclusive = 0
     }
 
     //Do numTrials for all plot points
     for (int t = 0; t < numTrials; t++) {
       sk.reset();
-      doTrial(sk, stream, trueValues, corrTrueValues, errQSkArr);
+      doTrial(sk, stream, trueNaturalRanks, corrNaturalRanks, errQSkArr);
     }
 
     //at this point each of the errQSkArr sketches has a distribution of error from numTrials
     for (int pp = 0 ; pp < numPlotPoints; pp++) {
-      final double v = trueValues[pp];
-      final double tr = v / streamLength; //the true rank
+      final double trueNatRank = trueNaturalRanks[pp];
+      final double trueNormalizedRank = trueNatRank / streamLength; //create the true normalized rank
 
       //for each of the numErrDistRanks distributions extract the sd quantiles
       final double[] errQ = errQSkArr[pp].getQuantiles(gRanks); //get error values at the Gaussian ranks
 
       //Plot the row. We ignore quantiles collected at 0 and 1.0.
       final double relPP = (double)(pp + 1) / numPlotPoints;
-      job.printfData(fFmt, relPP, v, tr,
+      job.printfData(fFmt, relPP, trueNatRank, trueNormalizedRank,
           errQ[0], errQ[1], errQ[2], errQ[3], errQ[4], errQ[5], errQ[6]);
       errQSkArr[pp].reset(); //reset the errQSkArr for next streamLength
     }
@@ -211,25 +224,31 @@ public class KllDoublesSketchRankGaussianAccuracyProfile implements JobProfile {
    * We capture the estimated ranks for all plotPoints and then update the errQSkArr with those
    * error values.
    * @param stream the source stream
-   * @param trueValues the true integer ranks at each of the plot points
+   * @param trueNatRanks input quantiles to getRanks and also true natural ranks at each of the plot points
    * @param errQSkArr the quantile error sketches for each plot point to be updated
    */
-  static void doTrial(final KllDoublesSketch sk, final double[] stream, final double[] trueValues,
-      final double[] corrTrueValues, final UpdateDoublesSketch[] errQSkArr) {
+  void doTrial(final KllDoublesSketch sk, final double[] stream, final double[] trueNatRanks,
+      final double[] corrNatRanks, final UpdateDoublesSketch[] errQSkArr) {
     Shuffle.shuffle(stream);
     final int sl = stream.length;
     for (int i = 0; i < sl; i++) {
       sk.update(stream[i]);
     }
-    final int numPP = trueValues.length;
+    final int numPP = trueNatRanks.length;
     //get estimated ranks from sketch for all plot points
-    final double[] estRanks = new double[numPP];
-    for (int pp = 0; pp < numPP; pp++) {
-      estRanks[pp] = sk.getRank(trueValues[pp]);
+    final double[] estRanks;// = new double[numPP];
+    if (useBulk) {
+      estRanks = sk.getRanks(trueNatRanks, criteria);
+    } else {
+      estRanks = new double[numPP];
+      for (int pp = 0; pp < numPP; pp++) {
+        estRanks[pp] = sk.getRank(trueNatRanks[pp], criteria);
+      }
     }
+
     //compute errors for each plotPoint
     for (int pp = 0; pp < numPP; pp++) {
-      final double errorAtPlotPoint = estRanks[pp] - corrTrueValues[pp] / sl;
+      final double errorAtPlotPoint = estRanks[pp] - corrNatRanks[pp] / sl;
       errQSkArr[pp].update(errorAtPlotPoint); //update each of the errQArr sketches
     }
   }
diff --git a/src/main/java/org/apache/datasketches/characterization/kll/KllSketchAccuracyProfile.java b/src/main/java/org/apache/datasketches/characterization/kll/KllSketchAccuracyProfile.java
deleted file mode 100644
index 1d55893..0000000
--- a/src/main/java/org/apache/datasketches/characterization/kll/KllSketchAccuracyProfile.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * 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.characterization.kll;
-
-import static org.apache.datasketches.characterization.Shuffle.shuffle;
-import static org.apache.datasketches.kll.KllSketch.getNormalizedRankError;
-
-import java.util.Arrays;
-import java.util.Random;
-
-import org.apache.datasketches.characterization.quantiles.BaseQuantilesAccuracyProfile;
-import org.apache.datasketches.kll.KllDoublesSketch;
-import org.apache.datasketches.kll.KllFloatsSketch;
-import org.apache.datasketches.memory.DefaultMemoryRequestServer;
-import org.apache.datasketches.memory.WritableMemory;
-
-/**
- * This captures the maximum rank error over T trials.
- * The stream is shuffled prior to each trial.
- * This handles either floats or doubles.
- * The input distribution can be either uniform random or contiguous integral values.
- * The input is shuffled for each trial.
- *
- * @author Lee Rhodes
- *
- */
-public class KllSketchAccuracyProfile extends BaseQuantilesAccuracyProfile {
-  public static Random random = new Random();
-  private static final DefaultMemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
-  private int k;
-  private int streamLength;
-  private float[] inputFloatValues;
-  private float[] floatQueryValues;
-  private double[] inputDoubleValues;
-  private double[] doubleQueryValues;
-  private int[] trueRanks;
-  private boolean useBulk;
-  private String dataType;
-  private boolean direct = false;    //heap is default
-  private boolean useDouble = false; //useFloat is default
-  private String distributionType;
-  private boolean uniformRandom = false;   //contiguous is default;
-  private double epsilon;
-  //add other types
-
-  KllDoublesSketch dskUT = null;
-  KllFloatsSketch fskUT = null;
-
-  @Override //BaseQuantilesAccuracyProfile
-  public void configure() {
-    k = Integer.parseInt(props.mustGet("K"));
-    epsilon = getNormalizedRankError(k, false);
-    useBulk = Boolean.parseBoolean(props.mustGet("useBulk"));
-    direct = Boolean.parseBoolean(props.mustGet("direct"));
-    dataType = props.mustGet("dataType");
-    if (dataType.equalsIgnoreCase("double")) { useDouble = true; }
-    distributionType = props.mustGet("distributionType");
-    if (distributionType.equalsIgnoreCase("uniformRandom")) { uniformRandom = true; }
-    configureSketchUnderTest();
-  }
-
-  private void configureSketchUnderTest() {
-    if (useDouble) {
-      if (direct) {
-        final WritableMemory dstMem = WritableMemory.allocate(10000);
-        dskUT = KllDoublesSketch.newDirectInstance(k, dstMem, memReqSvr);
-      } else { //heap
-        dskUT = KllDoublesSketch.newHeapInstance(k);
-      }
-    } else { //useFloat
-      if (direct) {
-        final WritableMemory dstMem = WritableMemory.allocate(10000);
-        fskUT = KllFloatsSketch.newDirectInstance(k, dstMem, memReqSvr);
-      } else { //heap
-        fskUT = KllFloatsSketch.newHeapInstance(k);
-      }
-    }
-  }
-
-  @Override //BaseQuantilesAccuracyProfile
-  // called once per streamLength.
-  //prepare input data that will be permuted and associated arrays
-  public void prepareTrialSet(final int streamLength) {
-    this.streamLength = streamLength;
-
-    if (useDouble) {
-      inputDoubleValues = new double[streamLength];
-      doubleQueryValues = new double[streamLength];
-      final int[] sortedArr = uniformRandom
-          ? fillUniformRandomDoubles(inputDoubleValues)
-          : fillContiguousDoubles(inputDoubleValues);
-      trueRanks = getTrueRanksDoubles(sortedArr, doubleQueryValues);
-      if (uniformRandom) { compressDoubleQueryValues(); }
-    }
-    else { //useFloats
-      inputFloatValues = new float[streamLength];
-      floatQueryValues = new float[streamLength];
-      final int[] sortedArr = uniformRandom
-          ? fillUniformRandomFloats(inputFloatValues)
-          : fillContiguousFloats(inputFloatValues);
-      trueRanks = getTrueRanksFloats(sortedArr, floatQueryValues);
-      if (uniformRandom) { compressFloatQueryValuesAndTrueRanks(); }
-    }
-  }
-
-  @Override
-  public double getEpsilon() {
-    return epsilon;
-  }
-
-  /**
-   * For each trial:
-   * <ul>
-   * <li>Feed the sketch under test (skUT) a shuffled stream of length SL of "true" values.</li>
-   * <li>Query the skUT for the estimated rank of each true value and capture the maximum
-   * error of all the estimated ranks</li>
-   * <li>Return this maximum error of this trial.</li>
-   * </ul>
-   */
-  @Override //BaseQuantilesAccuracyProfile
-  public double doTrial() {
-    double worstNegRankError = 0;
-    double worstPosRankError = 0;
-
-    if (useDouble) {
-      shuffle(inputDoubleValues);
-      // reset then update sketch
-      dskUT.reset();
-      for (int i = 0; i < streamLength; i++) {
-        dskUT.update(inputDoubleValues[i]);
-      }
-
-      // query sketch and gather results
-      worstNegRankError = 0;
-      worstPosRankError = 0;
-      final int queryLen = trueRanks.length;
-      if (useBulk) {
-        final double[] estRanks = dskUT.getCDF(doubleQueryValues);
-        for (int i = 0; i < queryLen; i++) {
-          final double trueRank = (double) trueRanks[i] / streamLength;
-          final double deltaRankErr = estRanks[i] - trueRank;
-          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
-          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
-        }
-      } else {
-        for (int i = 0; i < queryLen; i++) {
-          final double trueRank = (double) trueRanks[i] / streamLength;
-          final double deltaRankErr = dskUT.getRank(i) - trueRank;
-          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
-          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
-        }
-      }
-    }
-
-    else { //use Float
-      shuffle(inputFloatValues);
-      // reset then update sketch
-      fskUT.reset();
-      for (int i = 0; i < inputFloatValues.length; i++) {
-        fskUT.update(inputFloatValues[i]);
-      }
-
-      // query sketch and gather results
-      worstNegRankError = 0;
-      worstPosRankError = 0;
-      final int qLen = trueRanks.length;
-      if (useBulk) {
-        final double[] estRanks = fskUT.getCDF(floatQueryValues);
-        for (int i = 0; i < qLen; i++) {
-          final double trueRank = (double) trueRanks[i] / streamLength;
-          final double deltaRankErr = estRanks[i] - trueRank;
-          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
-          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
-        }
-      } else {
-        for (int i = 0; i < qLen; i++) {
-          final double trueRank = (double) trueRanks[i] / streamLength;
-          final double deltaRankErr = fskUT.getRank(i) - trueRank;
-          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
-          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
-        }
-      }
-    }
-    return (worstPosRankError > -worstNegRankError) ? worstPosRankError : worstNegRankError;
-  }
-
-  //************************************************
-
-  /**
-   * Create a set of <i>n</i> uniform random integral values in the range [0, n).
-   * They will not be sorted. There may be duplicates and, therefore, missing values.
-   * @param inputDoubleValues empty double[] of size <i>n</i>.
-   * @return sorted int[] of source integers
-   */
-  static final int[] fillUniformRandomDoubles(final double[] inputDoubleValues) {
-    final int n = inputDoubleValues.length;
-    final int[] valueSourceArr = new int[n];
-    for (int i = 0; i < n; i++) {
-      final int v = random.nextInt(n);
-      valueSourceArr[i] = v;
-      inputDoubleValues[i] = v;
-    }
-    final int[] sortedArr = valueSourceArr.clone();
-    Arrays.sort(sortedArr);
-    return sortedArr;
-  }
-
-  /**
-   * Create a set of <i>n</i> contiguous integral values in the range [0, n)..
-   * They may be sorted, but don't need to be. There are no duplicates and no gaps.
-   * @param inputDoubleValues empty double[] of size <i>n</i>.
-   * @return sorted int[] of source integers
-   */
-  static final int[] fillContiguousDoubles(final double[] inputDoubleValues) {
-    final int n = inputDoubleValues.length;
-    final int[] valueSourceArr = new int[n];
-    for (int i = 0; i < n; i++) {
-      valueSourceArr[i] = i;
-      inputDoubleValues[i] = i;
-    }
-    final int[] sortedArr = valueSourceArr.clone();
-    return sortedArr;
-  }
-
-  /**
-   * @param sortedArr of source integers of size <i>n</i>.
-   * @param doubleQueryValues empty double[] of size <i>n</i>.
-   * @return int[] of true ranks aligned to doubleQueryValues
-   */
-  static final int[] getTrueRanksDoubles(final int[] sortedArr, final double[] doubleQueryValues) {
-    final int n = doubleQueryValues.length;
-    final int[] trueRanks = new int[n];
-    int r;
-    trueRanks[0] = r = 0;
-    doubleQueryValues[0] = sortedArr[0];
-    for (int i = 1; i < n; i++) {
-      final int v;
-      doubleQueryValues[i] = v = sortedArr[i];
-      trueRanks[i] = (v == sortedArr[i - 1]) ? r : (r = i);
-    }
-    return trueRanks;
-  }
-
-  final void compressDoubleQueryValues() {
-    //find num duplicates
-    final int n = trueRanks.length;
-    int dups = 0;
-    final int[] tmpTrueRanks;
-    final double[] tmpDoubleQueryValues;
-    for (int i = 1; i < n; i++) {
-      if (trueRanks[i] == trueRanks[i - 1]) { dups++; }
-    }
-    if (dups == 0) { return; }
-    final int cLen = n - dups;
-    tmpTrueRanks = new int[cLen];
-    tmpDoubleQueryValues = new double[cLen];
-    int j = 0;
-    tmpTrueRanks[0] = trueRanks[0];
-    tmpDoubleQueryValues[0] = doubleQueryValues[0];
-    for (int i = 1; i < n; i++) {
-      if (trueRanks[i] == trueRanks[i - 1]) { continue; }
-      j++;
-      tmpTrueRanks[j] = trueRanks[i];
-      tmpDoubleQueryValues[j] = doubleQueryValues[i];
-    }
-    assert j + 1 == cLen : "(j + 1): " + (j + 1) + ", clen: " + cLen;
-    trueRanks = tmpTrueRanks;
-    doubleQueryValues = tmpDoubleQueryValues;
-  }
-
-  //************************************************
-
-  /**
-   * Create a set of <i>n</i> uniform random integral values in the range [0, n).
-   * They will not be sorted. There may be duplicates and, therefore, missing values.
-   * @param inputFloatValues empty float[] of size <i>n</i>.
-   * @return sorted int[] of source integers
-   */
-  static final int[] fillUniformRandomFloats(final float[] inputFloatValues) {
-    final int n = inputFloatValues.length;
-    final int[] valueSourceArr = new int[n];
-    for (int i = 0; i < n; i++) {
-      final int v = random.nextInt(n);
-      valueSourceArr[i] = v;
-      inputFloatValues[i] = v;
-    }
-    final int[] sortedArr = valueSourceArr.clone();
-    Arrays.sort(sortedArr);
-    return sortedArr;
-  }
-
-  /**
-   * Create a set of <i>n</i> contiguous integral values in the range [0, n).
-   * They may be sorted, but don't need to be. There are no duplicates and no gaps.
-   * @param inputFloatValues empty float[] of size <i>n</i>.
-   * @return sorted int[] of source integers
-   */
-  static final int[] fillContiguousFloats(final float[] inputFloatValues) {
-    final int n = inputFloatValues.length;
-    final int[] valueSourceArr = new int[n];
-    for (int i = 0; i < n; i++) {
-      valueSourceArr[i] = i;
-      inputFloatValues[i] = i;
-    }
-    final int[] sortedArr = valueSourceArr.clone();
-    return sortedArr;
-  }
-
-  /**
-   * @param sortedArr int[] of source integers of size <i>n</i>.
-   * @param floatQueryValues empty float[] of size <i>n</i>.
-   * @return int[] of true ranks aligned to floatQueryValues
-   */
-  static final int[] getTrueRanksFloats(final int[] sortedArr, final float[] floatQueryValues) {
-    final int n = floatQueryValues.length;
-    final int[] trueRanks = new int[n];
-    int r;
-    trueRanks[0] = r = 0;
-    floatQueryValues[0] = sortedArr[0];
-    for (int i = 1; i < n; i++) {
-      final int v;
-      floatQueryValues[i] = v = sortedArr[i];
-      trueRanks[i] = (v == sortedArr[i - 1]) ? r : (r = i);
-    }
-    return trueRanks;
-  }
-
-  final void compressFloatQueryValuesAndTrueRanks() {
-    //find num duplicates
-    final int n = trueRanks.length;
-    int dups = 0;
-    final int[] tmpTrueRanks;
-    final float[] tmpFloatQueryValues;
-    for (int i = 1; i < n; i++) {
-      if (trueRanks[i] == trueRanks[i - 1]) { dups++; }
-    }
-    if (dups == 0) { return; }
-    final int cLen = n - dups;
-    tmpTrueRanks = new int[cLen];
-    tmpFloatQueryValues = new float[cLen];
-    int j = 0;
-    tmpTrueRanks[0] = trueRanks[0];
-    tmpFloatQueryValues[0] = floatQueryValues[0];
-    for (int i = 1; i < n; i++) {
-      if (trueRanks[i] == trueRanks[i - 1]) { continue; }
-      j++;
-      tmpTrueRanks[j] = trueRanks[i];
-      tmpFloatQueryValues[j] = floatQueryValues[i];
-    }
-    assert j + 1 == cLen : "(j + 1): " + (j + 1) + ", clen: " + cLen;
-    trueRanks = tmpTrueRanks;
-    floatQueryValues = tmpFloatQueryValues;
-  }
-
-}
diff --git a/src/main/java/org/apache/datasketches/characterization/kll/KllWorstCaseSketchAccuracyProfile.java b/src/main/java/org/apache/datasketches/characterization/kll/KllWorstCaseSketchAccuracyProfile.java
new file mode 100644
index 0000000..99fe7f4
--- /dev/null
+++ b/src/main/java/org/apache/datasketches/characterization/kll/KllWorstCaseSketchAccuracyProfile.java
@@ -0,0 +1,280 @@
+/*
+ * 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.characterization.kll;
+
+import static org.apache.datasketches.characterization.Shuffle.shuffle;
+import static org.apache.datasketches.kll.KllSketch.getNormalizedRankError;
+import static org.apache.datasketches.quantilescommon.QuantileSearchCriteria.EXCLUSIVE;
+import static org.apache.datasketches.quantilescommon.QuantileSearchCriteria.INCLUSIVE;
+
+import org.apache.datasketches.DoubleIntIntTriple;
+import org.apache.datasketches.FloatIntIntTriple;
+import org.apache.datasketches.SpecialRandom;
+import org.apache.datasketches.characterization.quantiles.BaseQuantilesAccuracyProfile;
+import org.apache.datasketches.kll.KllDoublesSketch;
+import org.apache.datasketches.kll.KllFloatsSketch;
+import org.apache.datasketches.kll.KllSketch;
+import org.apache.datasketches.kll.KllSketch.SketchType;
+import org.apache.datasketches.memory.DefaultMemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.apache.datasketches.quantilescommon.QuantileSearchCriteria;
+
+/**
+ * This captures the maximum rank error over T trials.
+ * This handles either floats or doubles.
+ * The input distribution is integral values [1..n] (as either floats or doubles) that are shuffled for each trial.
+ * The input is shuffled for each trial.
+ *
+ * @author Lee Rhodes
+ *
+ */
+public class KllWorstCaseSketchAccuracyProfile extends BaseQuantilesAccuracyProfile {
+  private static final long EIGHT_PEBIBYTE = 1L << 53; //max integral value that a double can resolve
+  private static final int SIXTEEN_MEBIBYTE = 1 << 24; //max integral value that a float can resolve
+  private static SpecialRandom random = new SpecialRandom();
+  private static final DefaultMemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+  private int k;
+  private int streamLength;
+  private FloatIntIntTriple[] inputFloatValues;
+  private float[] floatQueryValues;
+  private int[] floatRankValues;
+  private DoubleIntIntTriple[] inputDoubleValues;
+  private double[] doubleQueryValues;
+  private int[] doubleRankValues;
+  private boolean useBulk;
+
+  private boolean direct = false;    //heap is default
+
+  private String distributionType;
+  private boolean contiguous = true;   //contiguous is default;
+  private double epsilon;
+  private QuantileSearchCriteria criteria;
+  private SketchType sketchType;
+  //add other types
+
+  KllDoublesSketch dskUT = null;
+  KllFloatsSketch fskUT = null;
+
+  @Override //BaseQuantilesAccuracyProfile
+  public void configure() {
+    k = Integer.parseInt(props.mustGet("K"));
+    epsilon = getNormalizedRankError(k, false);
+    useBulk = Boolean.parseBoolean(props.mustGet("useBulk"));
+    direct = Boolean.parseBoolean(props.mustGet("direct"));
+    final String dataType = props.mustGet("dataType");
+    if ( dataType.equalsIgnoreCase("double")) { sketchType = SketchType.DOUBLES_SKETCH; }
+    else if (dataType.equalsIgnoreCase("float")) { sketchType = SketchType.FLOATS_SKETCH; }
+    else { sketchType = SketchType.ITEMS_SKETCH; }
+    distributionType = props.mustGet("distributionType");
+    contiguous = (distributionType.equalsIgnoreCase("contiguous")) ? true : false;
+    criteria = props.mustGet("criteria").equalsIgnoreCase("INCLUSIVE") ? INCLUSIVE : EXCLUSIVE;
+    configureSketchUnderTest();
+  }
+
+  private void configureSketchUnderTest() {
+    final int memBytes = KllSketch.getMaxSerializedSizeBytes(k, streamLength, sketchType, true);
+    if (sketchType == SketchType.DOUBLES_SKETCH) {
+      if (direct) {
+        final WritableMemory dstMem = WritableMemory.allocate(memBytes);
+        dskUT = KllDoublesSketch.newDirectInstance(k, dstMem, memReqSvr);
+      } else { //heap
+        dskUT = KllDoublesSketch.newHeapInstance(k);
+      }
+    } else { //useFloat
+      if (direct) {
+        final WritableMemory dstMem = WritableMemory.allocate(memBytes);
+        fskUT = KllFloatsSketch.newDirectInstance(k, dstMem, memReqSvr);
+      } else { //heap
+        fskUT = KllFloatsSketch.newHeapInstance(k);
+      }
+    } // else item
+  }
+
+  @Override //BaseQuantilesAccuracyProfile
+  // called once per streamLength.
+  //prepare input data that will be permuted and associated arrays
+  public void prepareTrialSet(final int streamLength) {
+    this.streamLength = streamLength;
+
+    if (sketchType == SketchType.DOUBLES_SKETCH) {
+      inputDoubleValues = fillDoubleArrays(streamLength, contiguous);
+    }
+    else { //useFloats
+      inputFloatValues = fillFloatArrays(streamLength, contiguous);
+    }
+  }
+
+  @Override
+  public double getEpsilon() {
+    return epsilon;
+  }
+
+  /**
+   * For each trial:
+   * <ul>
+   * <li>Feed the sketch under test (skUT) a shuffled stream of length SL of "true" values.</li>
+   * <li>Query the skUT for the estimated rank of each true value and capture the maximum
+   * error of all the estimated ranks</li>
+   * <li>Return this maximum error of this trial.</li>
+   * </ul>
+   */
+  @Override //BaseQuantilesAccuracyProfile
+  public double doTrial() {
+    double worstNegRankError = 0;
+    double worstPosRankError = 0;
+
+    //DOUBLES SKETCH
+    if (sketchType == SketchType.DOUBLES_SKETCH) {
+      shuffle(inputDoubleValues);
+      doubleQueryValues = DoubleIntIntTriple.getValueArray(inputDoubleValues);
+      doubleRankValues = DoubleIntIntTriple.getRankArray(inputDoubleValues);
+      // reset then update sketch
+      dskUT.reset();
+      for (int i = 0; i < streamLength; i++) {
+        dskUT.update(inputDoubleValues[i].value);
+      }
+
+      // query sketch and gather results
+      worstNegRankError = 0;
+      worstPosRankError = 0;
+      final int queryLen = inputDoubleValues.length;
+      final int one = (criteria == EXCLUSIVE) ? 1 : 0;
+      if (useBulk) {
+        final double[] estRanks = dskUT.getRanks(doubleQueryValues);
+        for (int i = 0; i < queryLen; i++) {
+          final double trueNormRank = (double) (doubleRankValues[i] - one) / streamLength;
+          final double deltaRankErr = estRanks[i] - trueNormRank;
+          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
+          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
+        }
+      } else {
+        for (int i = 0; i < queryLen; i++) {
+          final double estRank = dskUT.getRank(doubleRankValues[i]);
+          final double trueNormRank = (double) (doubleRankValues[i] - one) / streamLength;
+          final double deltaRankErr = estRank - trueNormRank;
+          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
+          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
+        }
+      }
+    }
+    //FLOATS SKETCH
+    else {
+      shuffle(inputFloatValues);
+      floatQueryValues = FloatIntIntTriple.getValueArray(inputFloatValues);
+      floatRankValues = FloatIntIntTriple.getRankArray(inputFloatValues);
+      // reset then update sketch
+      fskUT.reset();
+      for (int i = 0; i < inputFloatValues.length; i++) {
+        fskUT.update(inputFloatValues[i].value);
+      }
+
+      // query sketch and gather results
+      worstNegRankError = 0;
+      worstPosRankError = 0;
+      final int queryLen = inputFloatValues.length;
+      final int one = (criteria == EXCLUSIVE) ? 1 : 0;
+      if (useBulk) {
+        final double[] estRanks = fskUT.getRanks(floatQueryValues);
+        for (int i = 0; i < queryLen; i++) {
+          final double normRank = (double) (floatRankValues[i] - one) / streamLength;
+          final double deltaRankErr = estRanks[i] - normRank;
+          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
+          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
+        }
+      } else {
+        for (int i = 0; i < queryLen; i++) {
+          final double estRank = fskUT.getRank(floatRankValues[i]);
+          final double normRank = (double) (floatRankValues[i] - one) / streamLength;
+          final double deltaRankErr = estRank - normRank;
+          if (deltaRankErr < 0) { worstNegRankError = Math.min(worstNegRankError, deltaRankErr); }
+          else { worstPosRankError = Math.max(worstPosRankError, deltaRankErr); }
+        }
+      }
+    }
+    return (worstPosRankError > -worstNegRankError) ? worstPosRankError : worstNegRankError;
+  }
+
+  //************************************************
+
+  /**
+   * Create a DoubleIntIntTriple of <i>n</i> integral double values with associated index and rank
+   * @param n the given size of the returned filled array.
+   * @param contiguous if true, the values will be from the range [1, n].
+   * Otherwise, the values will be uniform random values from the range [1, 2^53] when sorted by index.
+   * @return DoubleIntIntTriple array.
+   */
+  static final DoubleIntIntTriple[] fillDoubleArrays(final int n, final boolean contiguous) {
+    final DoubleIntIntTriple[] array = new DoubleIntIntTriple[n];
+
+    if (contiguous) {
+      for (int i = 0, r = 1; i < n; i++, r++) {
+        final DoubleIntIntTriple item  = array[i] = new DoubleIntIntTriple();
+        item.index = i;
+        item.value = r;
+        item.rank = r;
+      }
+    } else { //random
+      for (int i = 0; i < n; i++) {
+        final DoubleIntIntTriple item  = array[i] = new DoubleIntIntTriple();
+        item.index = i;
+        item.value = random.nextLong(EIGHT_PEBIBYTE) + 1L;
+      }
+      DoubleIntIntTriple.sortByValue(array);
+      for (int i = 0, r = 1; i < n; i++, r++) {
+        array[i].rank = r;
+      }
+      DoubleIntIntTriple.sortByIndex(array);
+    }
+    return array;
+  }
+
+  /**
+   * Create a FloatIntIntTriple of <i>n</i> integral float values with associated index and rank
+   * @param n the given size of the returned filled array.
+   * @param contiguous if true, the values will be from the range [1, n].
+   * Otherwise, the values will be uniform random values from the range [1, 2^24] when the array is sorted by index.
+   * @return FloatIntIntTriple array sorted by index.
+   */
+  static final FloatIntIntTriple[] fillFloatArrays(final int n, final boolean contiguous) {
+    final FloatIntIntTriple[] array = new FloatIntIntTriple[n];
+
+    if (contiguous) {
+      for (int i = 0, r = 1; i < n; i++, r++) {
+        final FloatIntIntTriple item  = array[i] = new FloatIntIntTriple();
+        item.index = i;
+        item.value = r;
+        item.rank = r;
+      }
+    } else { //random
+      for (int i = 0; i < n; i++) {
+        final FloatIntIntTriple item  = array[i] = new FloatIntIntTriple();
+        item.index = i;
+        item.value = random.nextInt(SIXTEEN_MEBIBYTE) + 1;
+      }
+      FloatIntIntTriple.sortByValue(array);
+      for (int i = 0, r = 1; i < n; i++, r++) {
+        array[i].rank = r;
+      }
+      FloatIntIntTriple.sortByIndex(array);
+    }
+    return array;
+  }
+
+}
diff --git a/src/main/java/org/apache/datasketches/characterization/uniquecount/BaseAccuracyProfile.java b/src/main/java/org/apache/datasketches/characterization/uniquecount/BaseAccuracyProfile.java
index ed9cca5..7cb62fe 100644
--- a/src/main/java/org/apache/datasketches/characterization/uniquecount/BaseAccuracyProfile.java
+++ b/src/main/java/org/apache/datasketches/characterization/uniquecount/BaseAccuracyProfile.java
@@ -282,7 +282,7 @@ public abstract class BaseAccuracyProfile implements JobProfile {
   }
 
   /**
-   * This removes possible duplicate values in the given splitpoints array.
+   * This removes possible duplicate values in the given splitPoints array.
    * @param splitPoints the given splitPoints
    * @return the reduced array of splitPoints
    */
diff --git a/src/main/resources/kll/KllDoublesSketchRankGaussianAccuracyJob.conf b/src/main/resources/kll/KllDoublesSketchRankGaussianAccuracyJob.conf
index 30fba1d..84c397b 100644
--- a/src/main/resources/kll/KllDoublesSketchRankGaussianAccuracyJob.conf
+++ b/src/main/resources/kll/KllDoublesSketchRankGaussianAccuracyJob.conf
@@ -15,27 +15,33 @@
 # specific language governing permissions and limitations
 # under the License.
 
-JobProfile=org.apache.datasketches.characterization.quantiles.KllDoublesSketchRankGaussianAccuracyProfile
+JobProfile=org.apache.datasketches.characterization.kll.KllDoublesSketchRankGaussianAccuracyProfile
 
-# Trials config (indep of sketch)
+# Trials config (independent of sketch)
 ## Stream lengths
 LgMin=11    # The starting stream length
-LgMax=11    # How high the stream length goes
+LgMax=11    # The ending stream length
 LgDelta=3   # If > 0, this is the lg Increment
 PPO=8       # The horizontal x-resolution of trials points
 
-LgTrials=14 # lgTrials at every stream length
+LgTrials=18 # lgTrials at every stream length
 ErrSkLgK=12   # parameter for the rank error distribution sketch
 
+## Distribution type
+distribution=monotonic #monotonic vs flat
+
+
 # Plotting
 NumPlotPoints=100 # number of plot points along the x-axis
 
 # Specific sketch config
 K=100 # sketch size and accuracy parameter
-
+criteria=INCLUSIVE #INCLUSIVE or EXCLUSIVE
+useBulk=false # query ranks using getRanks(arr) instead of separate getRank() for each value
+direct=false   # vs heap
 
 # Date-Time Profile
-TimeZone=PDT
-TimeZoneOffset=-25200000 # offset in millisec: PST (UTC-8) = -28_800_000  PDT (UTC-7) = -25_200_000
+TimeZone=PST
+TimeZoneOffset=-28800000 # offset in millisec: PST (UTC-8) = -28800000  PDT (UTC-7) = -25200000
 FileNameDateFormat=yyyyMMdd'_'HHmmssz
 ReadableDateFormat=yyyy/MM/dd HH:mm:ss 
\ No newline at end of file
diff --git a/src/main/resources/kll/KllSketchAccuracyJob.conf b/src/main/resources/kll/KllWorstCaseSketchAccuracyJob.conf
similarity index 73%
rename from src/main/resources/kll/KllSketchAccuracyJob.conf
rename to src/main/resources/kll/KllWorstCaseSketchAccuracyJob.conf
index 7724ab7..87c2136 100644
--- a/src/main/resources/kll/KllSketchAccuracyJob.conf
+++ b/src/main/resources/kll/KllWorstCaseSketchAccuracyJob.conf
@@ -15,21 +15,23 @@
 # specific language governing permissions and limitations
 # under the License.
 
-JobProfile=org.apache.datasketches.characterization.kll.KllSketchAccuracyProfile
+JobProfile=org.apache.datasketches.characterization.kll.KllWorstCaseSketchAccuracyProfile
 
 # Used by BaseQuantilesAccuracyProfile.doTrials()
 lgMin=0  # The starting stream length
 lgMax=20 # How high the stream length goes
 PPO=8    # The horizontal x-resolution of trials points
-trials=5000 # Trials at every stream length
+trials=10000 # Trials at every stream length
 errLgK=14 # parameter for the rank error distribution sketch
+criteria=INCLUSIVE # or EXCLUSIVE 
 
 # Used by KllSketchAccuracyProfile.configure(Properties)
 K=200 # sketch size and accuracy parameter
-useBulk=true # query ranks using getCDF() instead of separate getRank() for each value
+useBulk=false # query ranks using getRanks(arr) instead of separate getRank() for each value
 direct=false   # vs heap
-dataType=float # vs double
-distributionType=uniformRandom #uniformRandom vs contiguous
+dataType=float # float vs double vs item
+distributionType=contiguous #contiguous [1..n] vs uniform random on domain [1..Z]
+# Where if double, Z = 8 * 2^53, if float Z = 16 * 2^24
 
 #not used
 errPct=99 # percentile of the rank error distribution to report


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datasketches.apache.org
For additional commands, e-mail: commits-help@datasketches.apache.org